[Tarantool-patches] [PATCH v1] Divide test box/net.box

Alexander V. Tikhonov avtikhon at tarantool.org
Thu Apr 2 09:38:15 MSK 2020


box/net.box_bad_argument_gh-594.test.lua
box/net.box_call_blocks_gh-946.test.lua
box/net.box_collectgarbage_gh-3107.test.lua
box/net.box_connect_triggers.test.lua
box/net.box_console_connections_gh-2677.test.lua
box/net.box_count_inconsistent_gh-3262.test.lua
box/net.box_discard_gh-3107.test.lua
box/net.box_disconnect_gh-3859.test.lua
box/net.box_fiber-async_gh-3107.test.lua
box/net.box_field_names_gh-2978.test.lua
box/net.box_get_connection_object.test.lua
box/net.box_gibberish_gh-3900.test.lua
box/net.box_huge_data_gh-983.test.lua
box/net.box_incompatible_index-gh-1729.test.lua
box/net.box_incorrect_iterator_gh-841.test.lua
box/net.box_index_unique_flag_gh-4091.test.lua
box/net.box_iproto_hangs_gh-3464.test.lua
box/net.box_is_nullable_gh-3256.test.lua
box/net.box_leaks_gh-3629.test.lua
box/net.box_log_corrupted_rows_gh-4040.test.lua
box/net.box_long-poll_input_gh-3400.test.lua
box/net.box_methods_gh-3107.test.lua
box/net.box_msgpack_gh-2195.test.lua
box/net.box_on_schema_reload-gh-1904.test.lua
box/net.box_password_gh-1545.test.lua
box/net.box_permissions.test.lua
box/net.box_pseudo_objects_gh-2401.test.lua
box/net.box_raw_response_gh-3107.test.lua
box/net.box_readahead_gh-3958.test.lua
box/net.box_reconnect_after_gh-3164.test.lua
box/net.box_reconnect_after.test.lua
box/net.box_reload_schema_gh-636.test.lua
box/net.box_remote_method_gh-544.test.lua
box/net.box_roll_back_gh-822.test.lua
box/net.box_schema_change_gh-2666.test.lua
box/net.box_schema_change_gh-3107.test.lua
box/net.box_session_type_gh-2642.test.lua
box/net.box_space_format_gh-2402.test.lua
box/net.box_timeout_gh-1533.test.lua
box/net.box_timeout-gh-3107.test.lua
box/net.box_upsert_gh-970.test.lua
box/net.box_wait_connected_gh-3856.test.lua
---

Github: https://github.com/tarantool/tarantool/tree/avtikhon/divide_tests

 test/box/gh-3107_rest1_net.box.result         |  119 +
 test/box/net.box.result                       | 3932 -----------------
 test/box/net.box.test.lua                     | 1585 -------
 test/box/net.box_bad_argument_gh-594.result   |   38 +
 test/box/net.box_bad_argument_gh-594.test.lua |   17 +
 test/box/net.box_call_blocks_gh-946.result    |  124 +
 test/box/net.box_call_blocks_gh-946.test.lua  |   67 +
 .../box/net.box_collectgarbage_gh-3107.result |  120 +
 .../net.box_collectgarbage_gh-3107.test.lua   |   44 +
 test/box/net.box_connect_triggers.result      |   82 +
 test/box/net.box_connect_triggers.test.lua    |   27 +
 ...net.box_console_connections_gh-2677.result |   95 +
 ...t.box_console_connections_gh-2677.test.lua |   39 +
 .../net.box_count_inconsistent_gh-3262.result |  488 ++
 ...et.box_count_inconsistent_gh-3262.test.lua |  182 +
 test/box/net.box_discard_gh-3107.result       |  119 +
 test/box/net.box_discard_gh-3107.test.lua     |   44 +
 test/box/net.box_disconnect_gh-3859.result    |  113 +
 test/box/net.box_disconnect_gh-3859.test.lua  |   50 +
 test/box/net.box_fiber-async_gh-3107.result   |  115 +
 test/box/net.box_fiber-async_gh-3107.test.lua |   42 +
 test/box/net.box_field_names_gh-2978.result   |  101 +
 test/box/net.box_field_names_gh-2978.test.lua |   29 +
 test/box/net.box_get_connection_object.result |   40 +
 .../net.box_get_connection_object.test.lua    |   19 +
 test/box/net.box_gibberish_gh-3900.result     |   31 +
 test/box/net.box_gibberish_gh-3900.test.lua   |   13 +
 test/box/net.box_huge_data_gh-983.result      |   30 +
 test/box/net.box_huge_data_gh-983.test.lua    |   16 +
 .../net.box_incompatible_index-gh-1729.result |   99 +
 ...et.box_incompatible_index-gh-1729.test.lua |   33 +
 .../net.box_incorrect_iterator_gh-841.result  |  497 +++
 ...net.box_incorrect_iterator_gh-841.test.lua |  182 +
 .../net.box_index_unique_flag_gh-4091.result  |   28 +
 ...net.box_index_unique_flag_gh-4091.test.lua |   15 +
 test/box/net.box_iproto_hangs_gh-3464.result  |   31 +
 .../box/net.box_iproto_hangs_gh-3464.test.lua |   13 +
 test/box/net.box_is_nullable_gh-3256.result   |   97 +
 test/box/net.box_is_nullable_gh-3256.test.lua |   36 +
 test/box/net.box_leaks_gh-3629.result         |   51 +
 test/box/net.box_leaks_gh-3629.test.lua       |   20 +
 .../net.box_log_corrupted_rows_gh-4040.result |   72 +
 ...et.box_log_corrupted_rows_gh-4040.test.lua |   31 +
 .../net.box_long-poll_input_gh-3400.result    |   35 +
 .../net.box_long-poll_input_gh-3400.test.lua  |   19 +
 test/box/net.box_methods_gh-3107.result       |  277 ++
 test/box/net.box_methods_gh-3107.test.lua     |   96 +
 test/box/net.box_msgpack_gh-2195.result       |  527 +++
 test/box/net.box_msgpack_gh-2195.test.lua     |  192 +
 .../net.box_on_schema_reload-gh-1904.result   |  102 +
 .../net.box_on_schema_reload-gh-1904.test.lua |   65 +
 test/box/net.box_password_gh-1545.result      |   28 +
 test/box/net.box_password_gh-1545.test.lua    |   10 +
 test/box/net.box_permissions.result           |  186 +
 test/box/net.box_permissions.test.lua         |   66 +
 .../box/net.box_pseudo_objects_gh-2401.result |   55 +
 .../net.box_pseudo_objects_gh-2401.test.lua   |   23 +
 test/box/net.box_raw_response_gh-3107.result  |  123 +
 .../box/net.box_raw_response_gh-3107.test.lua |   46 +
 test/box/net.box_readahead_gh-3958.result     |   55 +
 test/box/net.box_readahead_gh-3958.test.lua   |   29 +
 test/box/net.box_reconnect_after.result       |   32 +
 test/box/net.box_reconnect_after.test.lua     |   16 +
 .../net.box_reconnect_after_gh-3164.result    |  119 +
 .../net.box_reconnect_after_gh-3164.test.lua  |   52 +
 test/box/net.box_reload_schema_gh-636.result  |  108 +
 .../box/net.box_reload_schema_gh-636.test.lua |   46 +
 test/box/net.box_remote_method_gh-544.result  |   95 +
 .../box/net.box_remote_method_gh-544.test.lua |   40 +
 test/box/net.box_roll_back_gh-822.result      |   68 +
 test/box/net.box_roll_back_gh-822.test.lua    |   42 +
 test/box/net.box_schema_change_gh-2666.result |   79 +
 .../net.box_schema_change_gh-2666.test.lua    |   28 +
 test/box/net.box_schema_change_gh-3107.result |  151 +
 .../net.box_schema_change_gh-3107.test.lua    |   55 +
 test/box/net.box_session_type_gh-2642.result  |   22 +
 .../box/net.box_session_type_gh-2642.test.lua |   11 +
 test/box/net.box_space_format_gh-2402.result  |   49 +
 .../box/net.box_space_format_gh-2402.test.lua |   23 +
 test/box/net.box_timeout-gh-3107.result       |  125 +
 test/box/net.box_timeout-gh-3107.test.lua     |   47 +
 test/box/net.box_timeout_gh-1533.result       |   89 +
 test/box/net.box_timeout_gh-1533.test.lua     |   45 +
 test/box/net.box_upsert_gh-970.result         |   49 +
 test/box/net.box_upsert_gh-970.test.lua       |   16 +
 .../box/net.box_wait_connected_gh-3856.result |   20 +
 .../net.box_wait_connected_gh-3856.test.lua   |    8 +
 87 files changed, 6778 insertions(+), 5517 deletions(-)
 create mode 100644 test/box/gh-3107_rest1_net.box.result
 delete mode 100644 test/box/net.box.result
 delete mode 100644 test/box/net.box.test.lua
 create mode 100644 test/box/net.box_bad_argument_gh-594.result
 create mode 100644 test/box/net.box_bad_argument_gh-594.test.lua
 create mode 100644 test/box/net.box_call_blocks_gh-946.result
 create mode 100644 test/box/net.box_call_blocks_gh-946.test.lua
 create mode 100644 test/box/net.box_collectgarbage_gh-3107.result
 create mode 100644 test/box/net.box_collectgarbage_gh-3107.test.lua
 create mode 100644 test/box/net.box_connect_triggers.result
 create mode 100644 test/box/net.box_connect_triggers.test.lua
 create mode 100644 test/box/net.box_console_connections_gh-2677.result
 create mode 100644 test/box/net.box_console_connections_gh-2677.test.lua
 create mode 100644 test/box/net.box_count_inconsistent_gh-3262.result
 create mode 100644 test/box/net.box_count_inconsistent_gh-3262.test.lua
 create mode 100644 test/box/net.box_discard_gh-3107.result
 create mode 100644 test/box/net.box_discard_gh-3107.test.lua
 create mode 100644 test/box/net.box_disconnect_gh-3859.result
 create mode 100644 test/box/net.box_disconnect_gh-3859.test.lua
 create mode 100644 test/box/net.box_fiber-async_gh-3107.result
 create mode 100644 test/box/net.box_fiber-async_gh-3107.test.lua
 create mode 100644 test/box/net.box_field_names_gh-2978.result
 create mode 100644 test/box/net.box_field_names_gh-2978.test.lua
 create mode 100644 test/box/net.box_get_connection_object.result
 create mode 100644 test/box/net.box_get_connection_object.test.lua
 create mode 100644 test/box/net.box_gibberish_gh-3900.result
 create mode 100644 test/box/net.box_gibberish_gh-3900.test.lua
 create mode 100644 test/box/net.box_huge_data_gh-983.result
 create mode 100644 test/box/net.box_huge_data_gh-983.test.lua
 create mode 100644 test/box/net.box_incompatible_index-gh-1729.result
 create mode 100644 test/box/net.box_incompatible_index-gh-1729.test.lua
 create mode 100644 test/box/net.box_incorrect_iterator_gh-841.result
 create mode 100644 test/box/net.box_incorrect_iterator_gh-841.test.lua
 create mode 100644 test/box/net.box_index_unique_flag_gh-4091.result
 create mode 100644 test/box/net.box_index_unique_flag_gh-4091.test.lua
 create mode 100644 test/box/net.box_iproto_hangs_gh-3464.result
 create mode 100644 test/box/net.box_iproto_hangs_gh-3464.test.lua
 create mode 100644 test/box/net.box_is_nullable_gh-3256.result
 create mode 100644 test/box/net.box_is_nullable_gh-3256.test.lua
 create mode 100644 test/box/net.box_leaks_gh-3629.result
 create mode 100644 test/box/net.box_leaks_gh-3629.test.lua
 create mode 100644 test/box/net.box_log_corrupted_rows_gh-4040.result
 create mode 100644 test/box/net.box_log_corrupted_rows_gh-4040.test.lua
 create mode 100644 test/box/net.box_long-poll_input_gh-3400.result
 create mode 100644 test/box/net.box_long-poll_input_gh-3400.test.lua
 create mode 100644 test/box/net.box_methods_gh-3107.result
 create mode 100644 test/box/net.box_methods_gh-3107.test.lua
 create mode 100644 test/box/net.box_msgpack_gh-2195.result
 create mode 100644 test/box/net.box_msgpack_gh-2195.test.lua
 create mode 100644 test/box/net.box_on_schema_reload-gh-1904.result
 create mode 100644 test/box/net.box_on_schema_reload-gh-1904.test.lua
 create mode 100644 test/box/net.box_password_gh-1545.result
 create mode 100644 test/box/net.box_password_gh-1545.test.lua
 create mode 100644 test/box/net.box_permissions.result
 create mode 100644 test/box/net.box_permissions.test.lua
 create mode 100644 test/box/net.box_pseudo_objects_gh-2401.result
 create mode 100644 test/box/net.box_pseudo_objects_gh-2401.test.lua
 create mode 100644 test/box/net.box_raw_response_gh-3107.result
 create mode 100644 test/box/net.box_raw_response_gh-3107.test.lua
 create mode 100644 test/box/net.box_readahead_gh-3958.result
 create mode 100644 test/box/net.box_readahead_gh-3958.test.lua
 create mode 100644 test/box/net.box_reconnect_after.result
 create mode 100644 test/box/net.box_reconnect_after.test.lua
 create mode 100644 test/box/net.box_reconnect_after_gh-3164.result
 create mode 100644 test/box/net.box_reconnect_after_gh-3164.test.lua
 create mode 100644 test/box/net.box_reload_schema_gh-636.result
 create mode 100644 test/box/net.box_reload_schema_gh-636.test.lua
 create mode 100644 test/box/net.box_remote_method_gh-544.result
 create mode 100644 test/box/net.box_remote_method_gh-544.test.lua
 create mode 100644 test/box/net.box_roll_back_gh-822.result
 create mode 100644 test/box/net.box_roll_back_gh-822.test.lua
 create mode 100644 test/box/net.box_schema_change_gh-2666.result
 create mode 100644 test/box/net.box_schema_change_gh-2666.test.lua
 create mode 100644 test/box/net.box_schema_change_gh-3107.result
 create mode 100644 test/box/net.box_schema_change_gh-3107.test.lua
 create mode 100644 test/box/net.box_session_type_gh-2642.result
 create mode 100644 test/box/net.box_session_type_gh-2642.test.lua
 create mode 100644 test/box/net.box_space_format_gh-2402.result
 create mode 100644 test/box/net.box_space_format_gh-2402.test.lua
 create mode 100644 test/box/net.box_timeout-gh-3107.result
 create mode 100644 test/box/net.box_timeout-gh-3107.test.lua
 create mode 100644 test/box/net.box_timeout_gh-1533.result
 create mode 100644 test/box/net.box_timeout_gh-1533.test.lua
 create mode 100644 test/box/net.box_upsert_gh-970.result
 create mode 100644 test/box/net.box_upsert_gh-970.test.lua
 create mode 100644 test/box/net.box_wait_connected_gh-3856.result
 create mode 100644 test/box/net.box_wait_connected_gh-3856.test.lua

diff --git a/test/box/gh-3107_rest1_net.box.result b/test/box/gh-3107_rest1_net.box.result
new file mode 100644
index 000000000..d9c59d1cf
--- /dev/null
+++ b/test/box/gh-3107_rest1_net.box.result
@@ -0,0 +1,119 @@
+fiber = require 'fiber'
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+---
+...
+box.schema.func.create('long_function')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+---
+...
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+---
+...
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+---
+...
+s = box.schema.create_space('test')
+---
+...
+pk = s:create_index('pk')
+---
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{2}
+---
+- [2]
+...
+s:replace{3}
+---
+- [3]
+...
+s:replace{4}
+---
+- [4]
+...
+c = net:connect(box.cfg.listen)
+---
+...
+--
+-- Check infinity timeout.
+--
+ret = nil
+---
+...
+_ = fiber.create(function() ret = c:call('long_function', {1, 2, 3}, {is_async = true}):wait_result() end)
+---
+...
+finalize_long()
+---
+...
+while not ret do fiber.sleep(0.01) end
+---
+...
+ret
+---
+- [1, 2, 3]
+...
+c:close()
+---
+...
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+c = net:connect(box.cfg.listen)
+---
+...
+future = c:eval('return long_function(...)', {1, 2, 3}, {is_async = true})
+---
+...
+future:result()
+---
+- null
+- Response is not ready
+...
+future:wait_result(0.01) -- Must fail on timeout.
+---
+- null
+- Timeout exceeded
+...
+finalize_long()
+---
+...
+future:wait_result(100)
+---
+- [1, 2, 3]
+...
+c:close()
+---
+...
+--
+-- Check that is_async does not work on a closed connection.
+--
+c:call('any_func', {}, {is_async = true})
+---
+- error: Connection closed
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
+c = net:connect(box.cfg.listen)
+---
+...
+c:close()
+---
+...
+s:drop()
+---
+...
diff --git a/test/box/net.box.result b/test/box/net.box.result
deleted file mode 100644
index e3dabf7d9..000000000
--- a/test/box/net.box.result
+++ /dev/null
@@ -1,3932 +0,0 @@
-remote = require 'net.box'
----
-...
-fiber = require 'fiber'
----
-...
-log = require 'log'
----
-...
-msgpack = require 'msgpack'
----
-...
-env = require('test_run')
----
-...
-test_run = env.new()
----
-...
-test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '")
----
-- true
-...
-test_run:cmd("setopt delimiter ';'")
----
-- true
-...
-function x_select(cn, space_id, index_id, iterator, offset, limit, key, opts)
-    local ret = cn:_request('select', opts, nil, space_id, index_id, iterator,
-                            offset, limit, key)
-    return ret
-end
-function x_fatal(cn) cn._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80') end
-test_run:cmd("setopt delimiter ''");
----
-...
-LISTEN = require('uri').parse(box.cfg.listen)
----
-...
-space = box.schema.space.create('net_box_test_space')
----
-...
-index = space:create_index('primary', { type = 'tree' })
----
-...
--- low level connection
-log.info("create connection")
----
-...
-cn = remote.connect(LISTEN.host, LISTEN.service)
----
-...
-log.info("state is %s", cn.state)
----
-...
-cn:ping()
----
-- true
-...
-log.info("ping is done")
----
-...
-cn:ping()
----
-- true
-...
-log.info("ping is done")
----
-...
-cn:ping()
----
-- true
-...
--- check permissions
-cn:call('unexists_procedure')
----
-- error: Execute access to function 'unexists_procedure' is denied for user 'guest'
-...
-function test_foo(a,b,c) return { {{ [a] = 1 }}, {{ [b] = 2 }}, c } end
----
-...
-cn:call('test_foo', {'a', 'b', 'c'})
----
-- error: Execute access to function 'test_foo' is denied for user 'guest'
-...
-cn:eval('return 2+2')
----
-- error: Execute access to universe '' is denied for user 'guest'
-...
-cn:close()
----
-...
--- connect and call without usage access
-box.schema.user.grant('guest','execute','universe')
----
-...
-box.schema.user.revoke('guest','usage','universe')
----
-...
-box.session.su("guest")
----
-...
-cn = remote.connect(LISTEN.host, LISTEN.service)
----
-...
-cn:call('test_foo', {'a', 'b', 'c'})
----
-- error: Usage access to universe '' is denied for user 'guest'
-...
-box.session.su("admin")
----
-...
-box.schema.user.grant('guest','usage','universe')
----
-...
-cn:close()
----
-...
-cn = remote.connect(box.cfg.listen)
----
-...
-cn:call('unexists_procedure')
----
-- error: Procedure 'unexists_procedure' is not defined
-...
-cn:call('test_foo', {'a', 'b', 'c'})
----
-- [[{'a': 1}], [{'b': 2}], 'c']
-...
-cn:call(nil, {'a', 'b', 'c'})
----
-- error: Procedure 'nil' is not defined
-...
-cn:eval('return 2+2')
----
-- 4
-...
-cn:eval('return 1, 2, 3')
----
-- 1
-- 2
-- 3
-...
-cn:eval('return ...', {1, 2, 3})
----
-- 1
-- 2
-- 3
-...
-cn:eval('return { k = "v1" }, true, {  xx = 10, yy = 15 }, nil')
----
-- {'k': 'v1'}
-- true
-- {'yy': 15, 'xx': 10}
-- null
-...
-cn:eval('return nil')
----
-- null
-...
-cn:eval('return')
----
-...
-cn:eval('error("exception")')
----
-- error: 'eval:1: exception'
-...
-cn:eval('box.error(0)')
----
-- error: Unknown error
-...
-cn:eval('!invalid expression')
----
-- error: 'eval:1: unexpected symbol near ''!'''
-...
--- box.commit() missing at return of CALL/EVAL
-function no_commit() box.begin() fiber.sleep(0.001) end
----
-...
-cn:call('no_commit')
----
-- error: Transaction is active at return from function
-...
-cn:eval('no_commit()')
----
-- error: Transaction is active at return from function
-...
-remote.self:eval('return 1+1, 2+2')
----
-- 2
-- 4
-...
-remote.self:eval('return')
----
-...
-remote.self:eval('error("exception")')
----
-- error: '[string "error("exception")"]:1: exception'
-...
-remote.self:eval('box.error(0)')
----
-- error: Unknown error
-...
-remote.self:eval('!invalid expression')
----
-- error: '[string "return !invalid expression"]:1: unexpected symbol near ''!'''
-...
-box.schema.user.revoke('guest', 'execute', 'universe')
----
-...
---
--- gh-822: net.box.call should roll back local transaction on error
---
-_ = box.schema.space.create('gh822')
----
-...
-_ = box.space.gh822:create_index('primary')
----
-...
-test_run:cmd("setopt delimiter ';'")
----
-- true
-...
--- rollback on invalid function
-function rollback_on_invalid_function()
-    box.begin()
-    box.space.gh822:insert{1, "netbox_test"}
-    pcall(remote.self.call, remote.self, 'invalid_function')
-    return box.space.gh822:get(1) == nil
-end;
----
-...
-rollback_on_invalid_function();
----
-- true
-...
--- rollback on call error
-function test_error() error('Some error') end;
----
-...
-function rollback_on_call_error()
-    box.begin()
-    box.space.gh822:insert{1, "netbox_test"}
-    pcall(remote.self.call, remote.self, 'test_error')
-    return box.space.gh822:get(1) == nil
-end;
----
-...
-rollback_on_call_error();
----
-- true
-...
--- rollback on eval
-function rollback_on_eval_error()
-    box.begin()
-    box.space.gh822:insert{1, "netbox_test"}
-    pcall(remote.self.eval, remote.self, "error('Some error')")
-    return box.space.gh822:get(1) == nil
-end;
----
-...
-rollback_on_eval_error();
----
-- true
-...
-test_run:cmd("setopt delimiter ''");
----
-- true
-...
-box.space.gh822:drop()
----
-...
-box.schema.user.grant('guest', 'read,write', 'space', 'net_box_test_space')
----
-...
-box.schema.user.grant('guest', 'execute', 'universe')
----
-...
-cn:close()
----
-...
-cn = remote.connect(box.cfg.listen)
----
-...
-x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 0xFFFFFFFF, 123)
----
-- []
-...
-space:insert{123, 345}
----
-- [123, 345]
-...
-x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 0, 123)
----
-- []
-...
-x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 1, 123)
----
-- - [123, 345]
-...
-x_select(cn, space.id, space.index.primary.id, box.index.EQ, 1, 1, 123)
----
-- []
-...
-cn.space[space.id]  ~= nil
----
-- true
-...
-cn.space.net_box_test_space ~= nil
----
-- true
-...
-cn.space.net_box_test_space ~= nil
----
-- true
-...
-cn.space.net_box_test_space.index ~= nil
----
-- true
-...
-cn.space.net_box_test_space.index.primary ~= nil
----
-- true
-...
-cn.space.net_box_test_space.index[space.index.primary.id] ~= nil
----
-- true
-...
-cn.space.net_box_test_space.index.primary:select(123)
----
-- - [123, 345]
-...
-cn.space.net_box_test_space.index.primary:select(123, { limit = 0 })
----
-- []
-...
-cn.space.net_box_test_space.index.primary:select(nil, { limit = 1, })
----
-- - [123, 345]
-...
-cn.space.net_box_test_space:insert{234, 1,2,3}
----
-- [234, 1, 2, 3]
-...
-cn.space.net_box_test_space:insert{234, 1,2,3}
----
-- error: Duplicate key exists in unique index 'primary' in space 'net_box_test_space'
-...
-cn.space.net_box_test_space.insert{234, 1,2,3}
----
-- error: 'builtin/box/schema.lua..."]:<line>: Use space:insert(...) instead of space.insert(...)'
-...
-cn.space.net_box_test_space:replace{354, 1,2,3}
----
-- [354, 1, 2, 3]
-...
-cn.space.net_box_test_space:replace{354, 1,2,4}
----
-- [354, 1, 2, 4]
-...
-cn.space.net_box_test_space:select{123}
----
-- - [123, 345]
-...
-space:select({123}, { iterator = 'GE' })
----
-- - [123, 345]
-  - [234, 1, 2, 3]
-  - [354, 1, 2, 4]
-...
-cn.space.net_box_test_space:select({123}, { iterator = 'GE' })
----
-- - [123, 345]
-  - [234, 1, 2, 3]
-  - [354, 1, 2, 4]
-...
-cn.space.net_box_test_space:select({123}, { iterator = 'GT' })
----
-- - [234, 1, 2, 3]
-  - [354, 1, 2, 4]
-...
-cn.space.net_box_test_space:select({123}, { iterator = 'GT', limit = 1 })
----
-- - [234, 1, 2, 3]
-...
-cn.space.net_box_test_space:select({123}, { iterator = 'GT', limit = 1, offset = 1 })
----
-- - [354, 1, 2, 4]
-...
-cn.space.net_box_test_space:select{123}
----
-- - [123, 345]
-...
-cn.space.net_box_test_space:update({123}, { { '+', 2, 1 } })
----
-- [123, 346]
-...
-cn.space.net_box_test_space:update(123, { { '+', 2, 1 } })
----
-- [123, 347]
-...
-cn.space.net_box_test_space:select{123}
----
-- - [123, 347]
-...
-cn.space.net_box_test_space:insert(cn.space.net_box_test_space:get{123}:update{ { '=', 1, 2 } })
----
-- [2, 347]
-...
-cn.space.net_box_test_space:delete{123}
----
-- [123, 347]
-...
-cn.space.net_box_test_space:select{2}
----
-- - [2, 347]
-...
-cn.space.net_box_test_space:select({234}, { iterator = 'LT' })
----
-- - [2, 347]
-...
-cn.space.net_box_test_space:update({1}, { { '+', 2, 2 } })
----
-...
-cn.space.net_box_test_space:delete{1}
----
-...
-cn.space.net_box_test_space:delete{2}
----
-- [2, 347]
-...
-cn.space.net_box_test_space:delete{2}
----
-...
--- test one-based indexing in splice operation (see update.test.lua)
-cn.space.net_box_test_space:replace({10, 'abcde'})
----
-- [10, 'abcde']
-...
-cn.space.net_box_test_space:update(10,  {{':', 2, 0, 0, '!'}})
----
-- error: 'SPLICE error on field 2: offset is out of bound'
-...
-cn.space.net_box_test_space:update(10,  {{':', 2, 1, 0, '('}})
----
-- [10, '(abcde']
-...
-cn.space.net_box_test_space:update(10,  {{':', 2, 2, 0, '({'}})
----
-- [10, '(({abcde']
-...
-cn.space.net_box_test_space:update(10,  {{':', 2, -1, 0, ')'}})
----
-- [10, '(({abcde)']
-...
-cn.space.net_box_test_space:update(10,  {{':', 2, -2, 0, '})'}})
----
-- [10, '(({abcde}))']
-...
-cn.space.net_box_test_space:delete{10}
----
-- [10, '(({abcde}))']
-...
-cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
----
-- - [234, 1, 2, 3]
-  - [354, 1, 2, 4]
-...
--- gh-841: net.box uses incorrect iterator type for select with no arguments
-cn.space.net_box_test_space:select()
----
-- - [234, 1, 2, 3]
-  - [354, 1, 2, 4]
-...
-cn.space.net_box_test_space.index.primary:min()
----
-- [234, 1, 2, 3]
-...
-cn.space.net_box_test_space.index.primary:min(354)
----
-- [354, 1, 2, 4]
-...
-cn.space.net_box_test_space.index.primary:max()
----
-- [354, 1, 2, 4]
-...
-cn.space.net_box_test_space.index.primary:max(234)
----
-- [234, 1, 2, 3]
-...
-cn.space.net_box_test_space.index.primary:count()
----
-- 2
-...
-cn.space.net_box_test_space.index.primary:count(354)
----
-- 1
-...
-cn.space.net_box_test_space:get(354)
----
-- [354, 1, 2, 4]
-...
--- reconnects after errors
-box.schema.user.revoke('guest', 'execute', 'universe')
----
-...
-box.schema.func.create('test_foo')
----
-...
-box.schema.user.grant('guest', 'execute', 'function', 'test_foo')
----
-...
--- -- 1. no reconnect
-x_fatal(cn)
----
-...
-cn.state
----
-- error
-...
-cn:ping()
----
-- false
-...
-cn:call('test_foo')
----
-- error: Peer closed
-...
-cn:wait_state('active')
----
-- false
-...
--- -- 2 reconnect
-cn = remote.connect(LISTEN.host, LISTEN.service, { reconnect_after = .1 })
----
-...
-cn.space ~= nil
----
-- true
-...
-cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
----
-- - [234, 1, 2, 3]
-  - [354, 1, 2, 4]
-...
-x_fatal(cn)
----
-...
-cn:wait_connected()
----
-- true
-...
-cn:wait_state('active')
----
-- true
-...
-cn:wait_state({active=true})
----
-- true
-...
-cn:ping()
----
-- true
-...
-cn.state
----
-- active
-...
-cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
----
-- - [234, 1, 2, 3]
-  - [354, 1, 2, 4]
-...
-x_fatal(cn)
----
-...
-x_select(cn, space.id, 0, box.index.ALL, 0, 0xFFFFFFFF, {})
----
-- - [234, 1, 2, 3]
-  - [354, 1, 2, 4]
-...
-cn.state
----
-- active
-...
-cn:ping()
----
-- true
-...
--- -- dot-new-method
-cn1 = remote.new(LISTEN.host, LISTEN.service)
----
-...
-x_select(cn1, space.id, 0, box.index.ALL, 0, 0xFFFFFFF, {})
----
-- - [234, 1, 2, 3]
-  - [354, 1, 2, 4]
-...
-cn1:close()
----
-...
--- -- error while waiting for response
-type(fiber.create(function() fiber.sleep(.5) x_fatal(cn) end))
----
-- userdata
-...
-function pause() fiber.sleep(10) return true end
----
-...
-box.schema.func.create('pause')
----
-...
-box.schema.user.grant('guest', 'execute', 'function', 'pause')
----
-...
-cn:call('pause')
----
-- error: Peer closed
-...
-cn:call('test_foo', {'a', 'b', 'c'})
----
-- [[{'a': 1}], [{'b': 2}], 'c']
-...
-box.schema.func.drop('pause')
----
-...
--- call
-remote.self:call('test_foo', {'a', 'b', 'c'})
----
-- - - a: 1
-  - - b: 2
-  - c
-...
-cn:call('test_foo', {'a', 'b', 'c'})
----
-- [[{'a': 1}], [{'b': 2}], 'c']
-...
-box.schema.func.drop('test_foo')
----
-...
-box.schema.func.create('long_rep')
----
-...
-box.schema.user.grant('guest', 'execute', 'function', 'long_rep')
----
-...
--- long replies
-function long_rep() return { 1,  string.rep('a', 5000) } end
----
-...
-res = cn:call('long_rep')
----
-...
-res[1] == 1
----
-- true
-...
-res[2] == string.rep('a', 5000)
----
-- true
-...
-function long_rep() return { 1,  string.rep('a', 50000) } end
----
-...
-res = cn:call('long_rep')
----
-...
-res[1] == 1
----
-- true
-...
-res[2] == string.rep('a', 50000)
----
-- true
-...
-box.schema.func.drop('long_rep')
----
-...
--- a.b.c.d
-u = '84F7BCFA-079C-46CC-98B4-F0C821BE833E'
----
-...
-X = {}
----
-...
-X.X = X
----
-...
-function X.fn(x,y) return y or x end
----
-...
-box.schema.user.grant('guest', 'execute', 'universe')
----
-...
-cn:close()
----
-...
-cn = remote.connect(LISTEN.host, LISTEN.service)
----
-...
-cn:call('X.fn', {u})
----
-- 84F7BCFA-079C-46CC-98B4-F0C821BE833E
-...
-cn:call('X.X.X.X.X.X.X.fn', {u})
----
-- 84F7BCFA-079C-46CC-98B4-F0C821BE833E
-...
-cn:call('X.X.X.X:fn', {u})
----
-- 84F7BCFA-079C-46CC-98B4-F0C821BE833E
-...
-box.schema.user.revoke('guest', 'execute', 'universe')
----
-...
-cn:close()
----
-...
--- auth
-cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123', wait_connected = true })
----
-...
-cn:is_connected()
----
-- false
-...
-cn.error
----
-- User 'netbox' is not found
-...
-cn.state
----
-- error
-...
-box.schema.user.create('netbox', { password  = 'test' })
----
-...
-box.schema.user.grant('netbox', 'read,write', 'space', 'net_box_test_space')
----
-...
-box.schema.user.grant('netbox', 'execute', 'universe')
----
-...
-cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = 'test' })
----
-...
-cn.state
----
-- active
-...
-cn.error
----
-- null
-...
-cn:ping()
----
-- true
-...
-function ret_after(to) fiber.sleep(to) return {{to}} end
----
-...
-cn:ping({timeout = 1.00})
----
-- true
-...
-cn:ping({timeout = 1e-9})
----
-- false
-...
-cn:ping()
----
-- true
-...
-remote_space = cn.space.net_box_test_space
----
-...
-remote_pk = remote_space.index.primary
----
-...
-remote_space:insert({0}, { timeout = 1.00 })
----
-- [0]
-...
-remote_space:insert({1}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_space:insert({2})
----
-- [2]
-...
-remote_space:replace({0}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_space:replace({1})
----
-- [1]
-...
-remote_space:replace({2}, { timeout = 1.00 })
----
-- [2]
-...
-remote_space:upsert({3}, {}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_space:upsert({4}, {})
----
-...
-remote_space:upsert({5}, {}, { timeout = 1.00 })
----
-...
-remote_space:upsert({3}, {})
----
-...
-remote_space:update({3}, {}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_space:update({4}, {})
----
-- [4]
-...
-remote_space:update({5}, {}, { timeout = 1.00 })
----
-- [5]
-...
-remote_space:update({3}, {})
----
-- [3]
-...
-remote_pk:update({5}, {}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_pk:update({4}, {})
----
-- [4]
-...
-remote_pk:update({3}, {}, { timeout = 1.00 })
----
-- [3]
-...
-remote_pk:update({5}, {})
----
-- [5]
-...
-remote_space:get({0})
----
-- [0]
-...
-remote_space:get({1}, { timeout = 1.00 })
----
-- [1]
-...
-remote_space:get({2}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_pk:get({3}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_pk:get({4})
----
-- [4]
-...
-remote_pk:get({5}, { timeout = 1.00 })
----
-- [5]
-...
-remote_space:select({2}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_space:select({2}, { timeout = 1.00 })
----
-- - [2]
-...
-remote_space:select({2})
----
-- - [2]
-...
-remote_pk:select({2}, { timeout = 1.00 })
----
-- - [2]
-...
-remote_pk:select({2}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_pk:select({2})
----
-- - [2]
-...
-remote_space:select({5}, { timeout = 1.00, iterator = 'LE', limit = 5 })
----
-- - [5]
-  - [4]
-  - [3]
-  - [2]
-  - [1]
-...
-remote_space:select({5}, { iterator = 'LE', limit = 5})
----
-- - [5]
-  - [4]
-  - [3]
-  - [2]
-  - [1]
-...
-remote_space:select({5}, { timeout = 1e-9, iterator = 'LE', limit = 5 })
----
-- error: Timeout exceeded
-...
-remote_pk:select({2}, { timeout = 1.00, iterator = 'LE', limit = 5 })
----
-- - [2]
-  - [1]
-  - [0]
-...
-remote_pk:select({2}, { iterator = 'LE', limit = 5})
----
-- - [2]
-  - [1]
-  - [0]
-...
-remote_pk:select({2}, { timeout = 1e-9, iterator = 'LE', limit = 5 })
----
-- error: Timeout exceeded
-...
-remote_pk:count({2}, { timeout = 1.00})
----
-- 1
-...
-remote_pk:count({2}, { timeout = 1e-9})
----
-- error: Timeout exceeded
-...
-remote_pk:count({2})
----
-- 1
-...
-remote_pk:count({2}, { timeout = 1.00, iterator = 'LE' })
----
-- 3
-...
-remote_pk:count({2}, { iterator = 'LE'})
----
-- 3
-...
-remote_pk:count({2}, { timeout = 1e-9, iterator = 'LE' })
----
-- error: Timeout exceeded
-...
-remote_pk:min(nil, { timeout = 1.00 })
----
-- [0]
-...
-remote_pk:min(nil, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_pk:min(nil)
----
-- [0]
-...
-remote_pk:min({0}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_pk:min({1})
----
-- [1]
-...
-remote_pk:min({2}, { timeout = 1.00 })
----
-- [2]
-...
-remote_pk:max(nil)
----
-- [354, 1, 2, 4]
-...
-remote_pk:max(nil, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_pk:max(nil, { timeout = 1.00 })
----
-- [354, 1, 2, 4]
-...
-remote_pk:max({0}, { timeout = 1.00 })
----
-- [0]
-...
-remote_pk:max({1}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-remote_pk:max({2})
----
-- [2]
-...
---
--- gh-3262: index:count() inconsistent results
---
-test_run:cmd("setopt delimiter ';'")
----
-- true
-...
-function do_count_test(min, it)
-    local r1 = remote_pk:count(min, {iterator = it} )
-    local r2 = box.space.net_box_test_space.index.primary:count(min, {iterator = it} )
-    local r3 = remote.self.space.net_box_test_space.index.primary:count(min, {iterator = it} )
-    return r1 == r2 and r2 == r3
-end;
----
-...
-data = remote_pk:select();
----
-...
-for _, v in pairs(data) do
-    local itrs = {'GE', 'GT', 'LE', 'LT' }
-    for _, it in pairs(itrs) do
-        assert(do_count_test(v[0], it) == true)
-    end
-end;
----
-...
-test_run:cmd("setopt delimiter ''");
----
-- true
-...
-_ = remote_space:delete({0}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-_ = remote_pk:delete({0}, { timeout = 1.00 })
----
-...
-_ = remote_space:delete({1}, { timeout = 1.00 })
----
-...
-_ = remote_pk:delete({1}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-_ = remote_space:delete({2}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-_ = remote_pk:delete({2})
----
-...
-_ = remote_pk:delete({3})
----
-...
-_ = remote_pk:delete({4})
----
-...
-_ = remote_pk:delete({5})
----
-...
-remote_space:get(0)
----
-...
-remote_space:get(1)
----
-...
-remote_space:get(2)
----
-...
-remote_space = nil
----
-...
-cn:call('ret_after', {0.01}, { timeout = 1.00 })
----
-- [[0.01]]
-...
-cn:call('ret_after', {1.00}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
-cn:eval('return ret_after(...)', {0.01}, { timeout = 1.00 })
----
-- [[0.01]]
-...
-cn:eval('return ret_after(...)', {1.00}, { timeout = 1e-9 })
----
-- error: Timeout exceeded
-...
---
--- :timeout()
--- @deprecated since 1.7.4
---
-cn:timeout(1).space.net_box_test_space.index.primary:select{234}
----
-- - [234, 1, 2, 3]
-...
-cn:call('ret_after', {.01})
----
-- [[0.01]]
-...
-cn:timeout(1):call('ret_after', {.01})
----
-- [[0.01]]
-...
-cn:timeout(.01):call('ret_after', {1})
----
-- error: Timeout exceeded
-...
-cn = remote:timeout(0.0000000001):connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' })
----
-...
-cn:close()
----
-...
-cn = remote:timeout(1):connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' })
----
-...
-remote.self:ping()
----
-- true
-...
-remote.self.space.net_box_test_space:select{234}
----
-- - [234, 1, 2, 3]
-...
-remote.self:timeout(123).space.net_box_test_space:select{234}
----
-- - [234, 1, 2, 3]
-...
-remote.self:is_connected()
----
-- true
-...
-remote.self:wait_connected()
----
-- true
-...
-cn:close()
----
-...
--- cleanup database after tests
-space:drop()
----
-...
--- #1545 empty password
-cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'test' })
----
-...
-cn ~= nil
----
-- true
-...
-cn:close()
----
-...
-cn = remote.connect(LISTEN.host, LISTEN.service, { password = 'test' })
----
-- error: 'net.box: user is not defined'
-...
-cn ~= nil
----
-- true
-...
-cn:close()
----
-...
--- #544 usage for remote[point]method
-cn = remote.connect(LISTEN.host, LISTEN.service)
----
-...
-box.schema.user.grant('guest', 'execute', 'universe')
----
-...
-cn:close()
----
-...
-cn = remote.connect(LISTEN.host, LISTEN.service)
----
-...
-cn:eval('return true')
----
-- true
-...
-cn.eval('return true')
----
-- error: 'Use remote:eval(...) instead of remote.eval(...):'
-...
-cn.ping()
----
-- error: 'Use remote:ping(...) instead of remote.ping(...):'
-...
-cn:close()
----
-...
-remote.self:eval('return true')
----
-- true
-...
-remote.self.eval('return true')
----
-- error: 'Use remote:eval(...) instead of remote.eval(...):'
-...
-box.schema.user.revoke('guest', 'execute', 'universe')
----
-...
--- uri as the first argument
-uri = string.format('%s:%s@%s:%s', 'netbox', 'test', LISTEN.host, LISTEN.service)
----
-...
-cn = remote.new(uri)
----
-...
-cn:ping()
----
-- true
-...
-cn:close()
----
-...
-uri = string.format('%s@%s:%s', 'netbox', LISTEN.host, LISTEN.service)
----
-...
-cn = remote.new(uri)
----
-...
-cn ~= nil, cn.state, cn.error
----
-- true
-- error
-- Incorrect password supplied for user 'netbox'
-...
-cn:close()
----
-...
--- don't merge creds from uri & opts
-remote.new(uri, { password = 'test' })
----
-- error: 'net.box: user is not defined'
-...
-cn = remote.new(uri, { user = 'netbox', password = 'test' })
----
-...
-cn:ping()
----
-- true
-...
-cn:close()
----
-...
-box.schema.user.drop('netbox')
----
-...
--- #594: bad argument #1 to 'setmetatable' (table expected, got number)
-box.schema.func.create('dostring')
----
-...
-box.schema.user.grant('guest', 'execute', 'function', 'dostring')
----
-...
-test_run:cmd("setopt delimiter ';'")
----
-- true
-...
-function gh594()
-    local cn = remote.connect(box.cfg.listen)
-    local ping = fiber.create(function() cn:ping() end)
-    cn:call('dostring', {'return 2 + 2'})
-    cn:close()
-end;
----
-...
-test_run:cmd("setopt delimiter ''");
----
-- true
-...
-gh594()
----
-...
-box.schema.func.drop('dostring')
----
-...
--- #636: Reload schema on demand
-sp = box.schema.space.create('test_old')
----
-...
-_ = sp:create_index('primary')
----
-...
-sp:insert{1, 2, 3}
----
-- [1, 2, 3]
-...
-box.schema.user.grant('guest', 'read', 'space', 'test_old')
----
-...
-con = remote.new(box.cfg.listen)
----
-...
-con:ping()
----
-- true
-...
-con.space.test_old:select{}
----
-- - [1, 2, 3]
-...
-con.space.test == nil
----
-- true
-...
-sp = box.schema.space.create('test')
----
-...
-_ = sp:create_index('primary')
----
-...
-sp:insert{2, 3, 4}
----
-- [2, 3, 4]
-...
-box.schema.user.grant('guest', 'read', 'space', 'test')
----
-...
-con.space.test == nil
----
-- true
-...
-con:reload_schema()
----
-...
-con.space.test:select{}
----
-- - [2, 3, 4]
-...
-box.space.test:drop()
----
-...
-box.space.test_old:drop()
----
-...
-con:close()
----
-...
-name = string.match(arg[0], "([^,]+)%.lua")
----
-...
-file_log = require('fio').open(name .. '.log', {'O_RDONLY', 'O_NONBLOCK'})
----
-...
-file_log:seek(0, 'SEEK_END') ~= 0
----
-- true
-...
-box.schema.user.grant('guest', 'execute', 'universe')
----
-...
-test_run:cmd("setopt delimiter ';'")
----
-- true
-...
-_ = fiber.create(
-   function()
-         local conn = require('net.box').new(box.cfg.listen)
-         conn:call('no_such_function', {})
-         conn:close()
-   end
-);
----
-...
-test_run:cmd("setopt delimiter ''");
----
-- true
-...
-test_run:wait_log('default', 'ER_NO_SUCH_PROC', nil, 10)
----
-- ER_NO_SUCH_PROC
-...
-box.schema.user.revoke('guest', 'execute', 'universe')
----
-...
---
--- gh-3900: tarantool can be crashed by sending gibberish to a
--- binary socket
---
-socket = require("socket")
----
-...
-sock = socket.tcp_connect(LISTEN.host, LISTEN.service)
----
-...
-data = string.fromhex("6783000000000000000000000000000000000000000000800000C8000000000000000000000000000000000000000000FFFF210100373208000000FFFF000055AAEB66486472530D02000000000010A0350001008000001000000000000000000000000000D05700")
----
-...
-sock:write(data)
----
-- 104
-...
-test_run:wait_log('default', 'ER_INVALID_MSGPACK: Invalid MsgPack %- packet body', nil, 10)
----
-- 'ER_INVALID_MSGPACK: Invalid MsgPack - packet body'
-...
-sock:close()
----
-- true
-...
--- gh-983 selecting a lot of data crashes the server or hangs the
--- connection
--- gh-983 test case: iproto connection selecting a lot of data
-_ = box.schema.space.create('test', { temporary = true })
----
-...
-_ = box.space.test:create_index('primary', {type = 'TREE', parts = {1,'unsigned'}})
----
-...
-data1k = "aaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhh"
----
-...
-for i = 0,10000 do box.space.test:insert{i, data1k} end
----
-...
-box.schema.user.grant('guest', 'read', 'space', 'test')
----
-...
-net = require('net.box')
----
-...
-c = net:connect(box.cfg.listen)
----
-...
-r = c.space.test:select(nil, {limit=5000})
----
-...
-box.space.test:drop()
----
-...
--- gh-970 gh-971 UPSERT over network
-_ = box.schema.space.create('test')
----
-...
-_ = box.space.test:create_index('primary', {type = 'TREE', parts = {1,'unsigned'}})
----
-...
-_ = box.space.test:create_index('covering', {type = 'TREE', parts = {1,'unsigned',3,'string',2,'unsigned'}})
----
-...
-_ = box.space.test:insert{1, 2, "string"}
----
-...
-box.schema.user.grant('guest', 'read,write', 'space', 'test')
----
-...
-c = net:connect(box.cfg.listen)
----
-...
-c.space.test:select{}
----
-- - [1, 2, 'string']
-...
-c.space.test:upsert({1, 2, 'nothing'}, {{'+', 2, 1}}) -- common update
----
-...
-c.space.test:select{}
----
-- - [1, 3, 'string']
-...
-c.space.test:upsert({2, 4, 'something'}, {{'+', 2, 1}}) -- insert
----
-...
-c.space.test:select{}
----
-- - [1, 3, 'string']
-  - [2, 4, 'something']
-...
-c.space.test:upsert({2, 4, 'nothing'}, {{'+', 3, 100500}}) -- wrong operation
----
-...
-c.space.test:select{}
----
-- - [1, 3, 'string']
-  - [2, 4, 'something']
-...
--- gh-1729 net.box index metadata incompatible with local metadata
-c.space.test.index.primary.parts
----
-- - type: unsigned
-    is_nullable: false
-    fieldno: 1
-...
-c.space.test.index.covering.parts
----
-- - type: unsigned
-    is_nullable: false
-    fieldno: 1
-  - type: string
-    is_nullable: false
-    fieldno: 3
-  - type: unsigned
-    is_nullable: false
-    fieldno: 2
-...
-box.space.test:drop()
----
-...
--- CALL vs CALL_16 in connect options
-function echo(...) return ... end
----
-...
-box.schema.user.grant('guest', 'execute', 'universe')
----
-...
-c = net.connect(box.cfg.listen)
----
-...
-c:call('echo', {42})
----
-- 42
-...
-c:eval('return echo(...)', {42})
----
-- 42
-...
--- invalid arguments
-c:call('echo', 42)
----
-- error: 'builtin/box/net_box.lua..."]:<line>: Use remote:call(func_name, {arg1, arg2, ...},
-    opts) instead of remote:call(func_name, arg1, arg2, ...)'
-...
-c:eval('return echo(...)', 42)
----
-- error: 'builtin/box/net_box.lua..."]:<line>: Use remote:eval(expression, {arg1, arg2, ...},
-    opts) instead of remote:eval(expression, arg1, arg2, ...)'
-...
-c:close()
----
-...
-c = net.connect(box.cfg.listen, {call_16 = true})
----
-...
-c:call('echo', 42)
----
-- - [42]
-...
-c:eval('return echo(...)', 42)
----
-- 42
-...
-c:close()
----
-...
-box.schema.user.revoke('guest', 'execute', 'universe')
----
-...
---
--- gh-2195 export pure msgpack from net.box
---
-space = box.schema.space.create('test')
----
-...
-_ = box.space.test:create_index('primary')
----
-...
-box.schema.user.grant('guest', 'read,write', 'space', 'test')
----
-...
-box.schema.user.grant('guest', 'execute', 'universe')
----
-...
-c = net.connect(box.cfg.listen)
----
-...
-ibuf = require('buffer').ibuf()
----
-...
-c:ping()
----
-- true
-...
-c.space.test ~= nil
----
-- true
-...
-c.space.test:replace({1, 'hello'})
----
-- [1, 'hello']
-...
--- replace
-c.space.test:replace({2}, {buffer = ibuf})
----
-- 9
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: [[2]]}
-...
--- replace + skip_header
-c.space.test:replace({2}, {buffer = ibuf, skip_header = true})
----
-- 7
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- [[2]]
-...
--- insert
-c.space.test:insert({3}, {buffer = ibuf})
----
-- 9
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: [[3]]}
-...
--- insert + skip_header
-_ = space:delete({3})
----
-...
-c.space.test:insert({3}, {buffer = ibuf, skip_header = true})
----
-- 7
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- [[3]]
-...
--- update
-c.space.test:update({3}, {}, {buffer = ibuf})
----
-- 9
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: [[3]]}
-...
-c.space.test.index.primary:update({3}, {}, {buffer = ibuf})
----
-- 9
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: [[3]]}
-...
--- update + skip_header
-c.space.test:update({3}, {}, {buffer = ibuf, skip_header = true})
----
-- 7
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- [[3]]
-...
-c.space.test.index.primary:update({3}, {}, {buffer = ibuf, skip_header = true})
----
-- 7
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- [[3]]
-...
--- upsert
-c.space.test:upsert({4}, {}, {buffer = ibuf})
----
-- 7
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: []}
-...
--- upsert + skip_header
-c.space.test:upsert({4}, {}, {buffer = ibuf, skip_header = true})
----
-- 5
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- []
-...
--- delete
-c.space.test:upsert({4}, {}, {buffer = ibuf})
----
-- 7
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: []}
-...
--- delete + skip_header
-c.space.test:upsert({4}, {}, {buffer = ibuf, skip_header = true})
----
-- 5
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- []
-...
--- select
-c.space.test.index.primary:select({3}, {iterator = 'LE', buffer = ibuf})
----
-- 19
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: [[3], [2], [1, 'hello']]}
-...
--- select + skip_header
-c.space.test.index.primary:select({3}, {iterator = 'LE', buffer = ibuf, skip_header = true})
----
-- 17
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- [[3], [2], [1, 'hello']]
-...
--- select
-len = c.space.test:select({}, {buffer = ibuf})
----
-...
-ibuf.rpos + len == ibuf.wpos
----
-- true
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-ibuf.rpos == ibuf.wpos
----
-- true
-...
-len
----
-- 21
-...
-result
----
-- {48: [[1, 'hello'], [2], [3], [4]]}
-...
--- select + skip_header
-len = c.space.test:select({}, {buffer = ibuf, skip_header = true})
----
-...
-ibuf.rpos + len == ibuf.wpos
----
-- true
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-ibuf.rpos == ibuf.wpos
----
-- true
-...
-len
----
-- 19
-...
-result
----
-- [[1, 'hello'], [2], [3], [4]]
-...
--- call
-c:call("echo", {1, 2, 3}, {buffer = ibuf})
----
-- 10
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: [1, 2, 3]}
-...
-c:call("echo", {}, {buffer = ibuf})
----
-- 7
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: []}
-...
-c:call("echo", nil, {buffer = ibuf})
----
-- 7
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: []}
-...
--- call + skip_header
-c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
----
-- 8
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- [1, 2, 3]
-...
-c:call("echo", {}, {buffer = ibuf, skip_header = true})
----
-- 5
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- []
-...
-c:call("echo", nil, {buffer = ibuf, skip_header = true})
----
-- 5
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- []
-...
--- eval
-c:eval("echo(...)", {1, 2, 3}, {buffer = ibuf})
----
-- 7
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: []}
-...
-c:eval("echo(...)", {}, {buffer = ibuf})
----
-- 7
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: []}
-...
-c:eval("echo(...)", nil, {buffer = ibuf})
----
-- 7
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: []}
-...
--- eval + skip_header
-c:eval("echo(...)", {1, 2, 3}, {buffer = ibuf, skip_header = true})
----
-- 5
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- []
-...
-c:eval("echo(...)", {}, {buffer = ibuf, skip_header = true})
----
-- 5
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- []
-...
-c:eval("echo(...)", nil, {buffer = ibuf, skip_header = true})
----
-- 5
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- []
-...
--- make several request into a buffer with skip_header, then read
--- results
-c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
----
-- 8
-...
-c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
----
-- 8
-...
-c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
----
-- 8
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- [1, 2, 3]
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- [1, 2, 3]
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- [1, 2, 3]
-...
--- unsupported methods
-c.space.test:get({1}, { buffer = ibuf})
----
-- error: 'builtin/box/net_box.lua..."]:<line>: index:get() doesn''t support `buffer` argument'
-...
-c.space.test.index.primary:min({}, { buffer = ibuf})
----
-- error: 'builtin/box/net_box.lua..."]:<line>: index:min() doesn''t support `buffer` argument'
-...
-c.space.test.index.primary:max({}, { buffer = ibuf})
----
-- error: 'builtin/box/net_box.lua..."]:<line>: index:max() doesn''t support `buffer` argument'
-...
-c.space.test.index.primary:count({}, { buffer = ibuf})
----
-- error: 'builtin/box/net_box.lua..."]:<line>: index:count() doesn''t support `buffer` argument'
-...
-c.space.test.index.primary:get({1}, { buffer = ibuf})
----
-- error: 'builtin/box/net_box.lua..."]:<line>: index:get() doesn''t support `buffer` argument'
-...
--- error handling
-rpos, wpos = ibuf.rpos, ibuf.wpos
----
-...
-c.space.test:insert({1}, {buffer = ibuf})
----
-- error: Duplicate key exists in unique index 'primary' in space 'test'
-...
-ibuf.rpos == rpos, ibuf.wpos == wpos
----
-- true
-- true
-...
-ibuf = nil
----
-...
-c:close()
----
-...
-space:drop()
----
-...
-box.schema.user.revoke('guest', 'execute', 'universe')
----
-...
--- gh-1904 net.box hangs in :close() if a fiber was cancelled
--- while blocked in :_wait_state() in :_request()
-options = {user = 'netbox', password = 'badpass', wait_connected = false, reconnect_after = 0.01}
----
-...
-c = net:new(box.cfg.listen, options)
----
-...
-f = fiber.create(function() c:call("") end)
----
-...
-fiber.sleep(0.01)
----
-...
-f:cancel(); c:close()
----
-...
-box.schema.user.grant('guest', 'read', 'space', '_schema')
----
-...
--- check for on_schema_reload callback
-test_run:cmd("setopt delimiter ';'")
----
-- true
-...
-do
-    local a = 0
-    function osr_cb()
-        a = a + 1
-    end
-    local con = net.new(box.cfg.listen, {
-        wait_connected = false
-    })
-    con:on_schema_reload(osr_cb)
-    con:wait_connected()
-    con.space._schema:select{}
-    box.schema.space.create('misisipi')
-    box.space.misisipi:drop()
-    con.space._schema:select{}
-    con:close()
-    con = nil
-
-    return a
-end;
----
-- 2
-...
-do
-    local a = 0
-    function osr_cb()
-        a = a + 1
-    end
-    local con = net.new(box.cfg.listen, {
-        wait_connected = true
-    })
-    con:on_schema_reload(osr_cb)
-    con.space._schema:select{}
-    box.schema.space.create('misisipi')
-    box.space.misisipi:drop()
-    con.space._schema:select{}
-    con:close()
-    con = nil
-
-    return a
-end;
----
-- 1
-...
-test_run:cmd("setopt delimiter ''");
----
-- true
-...
-box.schema.user.revoke('guest', 'read', 'space', '_schema')
----
-...
--- Tarantool < 1.7.1 compatibility (gh-1533)
-c = net.new(box.cfg.listen)
----
-...
-c:ping()
----
-- true
-...
-c:close()
----
-...
--- Test for connect_timeout > 0 in netbox connect
-test_run:cmd("setopt delimiter ';'");
----
-- true
-...
-need_stop = false;
----
-...
-greeting =
-"Tarantool 1.7.3 (Lua console)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" ..
-"type 'help' for interactive help~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
----
-...
-socket = require('socket');
----
-...
-srv = socket.tcp_server('localhost', 0, {
-    handler = function(fd)
-        local fiber = require('fiber')
-        while not need_stop do
-            fiber.sleep(0.01)
-        end
-        fd:write(greeting)
-    end
-});
----
-...
--- we must get timeout
-port = srv:name().port
-nb = net.new('localhost:' .. port, {
-    wait_connected = true, console = true,
-    connect_timeout = 0.1
-});
----
-...
-nb.error:find('timed out') ~= nil;
----
-- true
-...
-need_stop = true
-nb:close();
----
-...
--- we must get peer closed
-nb = net.new('localhost:' .. port, {
-    wait_connected = true, console = true,
-    connect_timeout = 0.2
-});
----
-...
-nb.error ~= "Timeout exceeded";
----
-- true
-...
-nb:close();
----
-...
-test_run:cmd("setopt delimiter ''");
----
-- true
-...
-srv:close()
----
-- true
-...
-test_run:cmd("clear filter")
----
-- true
-...
---
--- gh-2402 net.box doesn't support space:format()
---
-space = box.schema.space.create('test', {format={{name="id", type="unsigned"}}})
----
-...
-space ~= nil
----
-- true
-...
-_ = box.space.test:create_index('primary')
----
-...
-box.schema.user.grant('guest', 'read', 'space', 'test')
----
-...
-c = net.connect(box.cfg.listen)
----
-...
-c:ping()
----
-- true
-...
-c.space.test ~= nil
----
-- true
-...
-format = c.space.test:format()
----
-...
-format[1] ~= nil
----
-- true
-...
-format[1].name == "id"
----
-- true
-...
-format[1].type == "unsigned"
----
-- true
-...
-c.space.test:format({})
----
-- error: net.box does not support setting space format
-...
---
--- gh-4091: index unique flag is always false.
---
-c.space.test.index.primary.unique
----
-- true
-...
-c:close()
----
-...
-space:drop()
----
-...
---
--- Check that it's possible to get connection object form net.box space
---
-space = box.schema.space.create('test', {format={{name="id", type="unsigned"}}})
----
-...
-space ~= nil
----
-- true
-...
-_ = box.space.test:create_index('primary')
----
-...
-box.schema.user.grant('guest','read,write,execute','space', 'test')
----
-...
-c = net.connect(box.cfg.listen)
----
-...
-c:ping()
----
-- true
-...
-c.space.test ~= nil
----
-- true
-...
-c.space.test.connection == c
----
-- true
-...
-box.schema.user.revoke('guest','read,write,execute','space', 'test')
----
-...
-c:close()
----
-...
---
--- gh-2642: box.session.type()
---
-box.schema.user.grant('guest','execute','universe')
----
-...
-c = net.connect(box.cfg.listen)
----
-...
-c:call("box.session.type")
----
-- binary
-...
-c:close()
----
-...
-box.schema.user.revoke('guest', 'execute', 'universe')
----
-...
---
--- On_connect/disconnect triggers.
---
-test_run:cmd('create server connecter with script = "box/proxy.lua"')
----
-- true
-...
-test_run:cmd('start server connecter')
----
-- true
-...
-test_run:cmd("set variable connect_to to 'connecter.listen'")
----
-- true
-...
-conn = net.connect(connect_to, { reconnect_after = 0.1 })
----
-...
-conn.state
----
-- active
-...
-connected_cnt = 0
----
-...
-disconnected_cnt = 0
----
-...
-function on_connect() connected_cnt = connected_cnt + 1 end
----
-...
-function on_disconnect() disconnected_cnt = disconnected_cnt + 1 end
----
-...
-conn:on_connect(on_connect)
----
-...
-conn:on_disconnect(on_disconnect)
----
-...
-test_run:cmd('stop server connecter')
----
-- true
-...
-test_run:cmd('start server connecter')
----
-- true
-...
-while conn.state ~= 'active' do fiber.sleep(0.1) end
----
-...
-connected_cnt
----
-- 1
-...
-old_disconnected_cnt = disconnected_cnt
----
-...
-disconnected_cnt >= 1
----
-- true
-...
-conn:close()
----
-...
-disconnected_cnt == old_disconnected_cnt + 1
----
-- true
-...
-test_run:cmd('stop server connecter')
----
-- true
-...
---
--- gh-2401 update pseudo objects not replace them
---
-space:drop()
----
-...
-space = box.schema.space.create('test')
----
-...
-box.schema.user.grant('guest', 'read', 'space', 'test')
----
-...
-c = net.connect(box.cfg.listen)
----
-...
-cspace = c.space.test
----
-...
-space.index.test_index == nil
----
-- true
-...
-cspace.index.test_index == nil
----
-- true
-...
-_ = space:create_index("test_index", {parts={1, 'string'}})
----
-...
-c:reload_schema()
----
-...
-space.index.test_index ~= nil
----
-- true
-...
-cspace.index.test_index ~= nil
----
-- true
-...
-c.space.test.index.test_index ~= nil
----
-- true
-...
--- cleanup
-space:drop()
----
-...
---
--- gh-946: long polling CALL blocks input
---
-box.schema.func.create('fast_call')
----
-...
-box.schema.func.create('long_call')
----
-...
-box.schema.func.create('wait_signal')
----
-...
-box.schema.user.grant('guest', 'execute', 'function', 'fast_call')
----
-...
-box.schema.user.grant('guest', 'execute', 'function', 'long_call')
----
-...
-box.schema.user.grant('guest', 'execute', 'function', 'wait_signal')
----
-...
-c = net.connect(box.cfg.listen)
----
-...
-N = 100
----
-...
-pad = string.rep('x', 1024)
----
-...
-long_call_cond = fiber.cond()
----
-...
-long_call_channel = fiber.channel()
----
-...
-fast_call_channel = fiber.channel()
----
-...
-function fast_call(x) return x end
----
-...
-function long_call(x) long_call_cond:wait() return x * 2 end
----
-...
-test_run:cmd("setopt delimiter ';'")
----
-- true
-...
-for i = 1, N do
-    fiber.create(function()
-        fast_call_channel:put(c:call('fast_call', {i, pad}))
-    end)
-    fiber.create(function()
-        long_call_channel:put(c:call('long_call', {i, pad}))
-    end)
-end
-test_run:cmd("setopt delimiter ''");
----
-...
-x = 0
----
-...
-for i = 1, N do x = x + fast_call_channel:get() end
----
-...
-x
----
-- 5050
-...
-long_call_cond:broadcast()
----
-...
-x = 0
----
-...
-for i = 1, N do x = x + long_call_channel:get() end
----
-...
-x
----
-- 10100
-...
---
--- Check that a connection does not leak if there is
--- a long CALL in progress when it is closed.
---
-disconnected = false
----
-...
-function on_disconnect() disconnected = true end
----
-...
--- Make sure all dangling connections are collected so
--- that on_disconnect trigger isn't called spuriously.
-collectgarbage('collect')
----
-- 0
-...
-fiber.sleep(0)
----
-...
-box.session.on_disconnect(on_disconnect) == on_disconnect
----
-- true
-...
---
--- gh-3859: on_disconnect is called only after all requests are
--- processed, but should be called right after disconnect and
--- only once.
---
-ch1 = fiber.channel(1)
----
-...
-ch2 = fiber.channel(1)
----
-...
-function wait_signal() ch1:put(true) ch2:get() end
----
-...
-_ = fiber.create(function() c:call('wait_signal') end)
----
-...
-ch1:get()
----
-- true
-...
-c:close()
----
-...
-fiber.sleep(0)
----
-...
-while disconnected == false do fiber.sleep(0.01) end
----
-...
-disconnected -- true
----
-- true
-...
-disconnected = nil
----
-...
-ch2:put(true)
----
-- true
-...
-fiber.sleep(0)
----
-...
-disconnected -- nil, on_disconnect is not called second time.
----
-- null
-...
-box.session.on_disconnect(nil, on_disconnect)
----
-...
-box.schema.func.drop('long_call')
----
-...
-box.schema.func.drop('fast_call')
----
-...
-box.schema.func.drop('wait_signal')
----
-...
---
--- gh-2666: check that netbox.call is not repeated on schema
--- change.
---
-box.schema.user.grant('guest', 'write', 'space', '_space')
----
-...
-box.schema.user.grant('guest', 'write', 'space', '_schema')
----
-...
-box.schema.user.grant('guest', 'create', 'universe')
----
-...
-count = 0
----
-...
-function create_space(name) count = count + 1 box.schema.create_space(name) return true end
----
-...
-box.schema.func.create('create_space')
----
-...
-box.schema.user.grant('guest', 'execute', 'function', 'create_space')
----
-...
-c = net.connect(box.cfg.listen)
----
-...
-c:call('create_space', {'test1'})
----
-- true
-...
-count
----
-- 1
-...
-c:call('create_space', {'test2'})
----
-- true
-...
-count
----
-- 2
-...
-c:call('create_space', {'test3'})
----
-- true
-...
-count
----
-- 3
-...
-box.space.test1:drop()
----
-...
-box.space.test2:drop()
----
-...
-box.space.test3:drop()
----
-...
-box.schema.user.revoke('guest', 'write', 'space', '_space')
----
-...
-box.schema.user.revoke('guest', 'write', 'space', '_schema')
----
-...
-box.schema.user.revoke('guest', 'create', 'universe')
----
-...
-c:close()
----
-...
-box.schema.func.drop('create_space')
----
-...
---
--- gh-3164: netbox connection is not closed and garbage collected
--- ever, if reconnect_after is set.
---
-test_run:cmd('start server connecter')
----
-- true
-...
-test_run:cmd("set variable connect_to to 'connecter.listen'")
----
-- true
-...
-weak = setmetatable({}, {__mode = 'v'})
----
-...
--- Create strong and weak reference. Weak is valid until strong
--- is valid too.
-strong = net.connect(connect_to, {reconnect_after = 0.1})
----
-...
-weak.c = strong
----
-...
-weak.c:ping()
----
-- true
-...
-test_run:cmd('stop server connecter')
----
-- true
-...
-test_run:cmd('cleanup server connecter')
----
-- true
-...
--- Check the connection tries to reconnect at least two times.
--- 'Cannot assign requested address' is the crutch for running the
--- tests in a docker. This error emits instead of
--- 'Connection refused' inside a docker.
-old_log_level = box.cfg.log_level
----
-...
-box.cfg{log_level = 6}
----
-...
-log.info(string.rep('a', 1000))
----
-...
-test_run:cmd("setopt delimiter ';'")
----
-- true
-...
-while test_run:grep_log('default', 'Network is unreachable', 1000) == nil and
-      test_run:grep_log('default', 'Connection refused', 1000) == nil and
-      test_run:grep_log('default', 'Cannot assign requested address', 1000) == nil do
-       fiber.sleep(0.1)
-end;
----
-...
-log.info(string.rep('a', 1000));
----
-...
-while test_run:grep_log('default', 'Network is unreachable', 1000) == nil and
-      test_run:grep_log('default', 'Connection refused', 1000) == nil and
-      test_run:grep_log('default', 'Cannot assign requested address', 1000) == nil do
-       fiber.sleep(0.1)
-end;
----
-...
-test_run:cmd("setopt delimiter ''");
----
-- true
-...
-box.cfg{log_level = old_log_level}
----
-...
-collectgarbage('collect')
----
-- 0
-...
-strong.state
----
-- error_reconnect
-...
-strong == weak.c
----
-- true
-...
--- Remove single strong reference. Now connection must be garbage
--- collected.
-strong = nil
----
-...
-collectgarbage('collect')
----
-- 0
-...
--- Now weak.c is null, because it was weak reference, and the
--- connection is deleted by 'collect'.
-weak.c
----
-- null
-...
---
--- gh-2677: netbox supports console connections, that complicates
--- both console and netbox. It was necessary because before a
--- connection is established, a console does not known is it
--- binary or text protocol, and netbox could not be created from
--- existing socket.
---
-box.schema.user.grant('guest', 'execute', 'universe')
----
-...
-urilib = require('uri')
----
-...
-uri = urilib.parse(tostring(box.cfg.listen))
----
-...
-s, greeting = net.establish_connection(uri.host, uri.service)
----
-...
-c = net.wrap(s, greeting, uri.host, uri.service, {reconnect_after = 0.01})
----
-...
-c.state
----
-- active
-...
-a = 100
----
-...
-function kek(args) return {1, 2, 3, args} end
----
-...
-c:eval('a = 200')
----
-...
-a
----
-- 200
-...
-c:call('kek', {300})
----
-- [1, 2, 3, 300]
-...
-s = box.schema.create_space('test')
----
-...
-box.schema.user.grant('guest', 'read,write', 'space', 'test')
----
-...
-pk = s:create_index('pk')
----
-...
-c:reload_schema()
----
-...
-c.space.test:replace{1}
----
-- [1]
-...
-c.space.test:get{1}
----
-- [1]
-...
-c.space.test:delete{1}
----
-- [1]
-...
---
--- Break a connection to test reconnect_after.
---
-_ = c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80')
----
-...
-while not c:is_connected() do fiber.sleep(0.01) end
----
-...
-c:ping()
----
-- true
-...
-s:drop()
----
-...
-c:close()
----
-...
---
--- Test a case, when netbox can not connect first time, but
--- reconnect_after is set.
---
-c = net.connect('localhost:33333', {reconnect_after = 0.1, wait_connected = false})
----
-...
-while c.state ~= 'error_reconnect' do fiber.sleep(0.01) end
----
-...
-c:close()
----
-...
-box.schema.user.revoke('guest', 'execute', 'universe')
----
-...
-c.state
----
-- closed
-...
-c = nil
----
-...
---
--- gh-3256 net.box is_nullable and collation options output
---
-space = box.schema.create_space('test')
----
-...
-box.schema.user.grant('guest', 'read', 'space', 'test')
----
-...
-_ = space:create_index('pk')
----
-...
-_ = space:create_index('sk', {parts = {{2, 'unsigned', is_nullable = true}}})
----
-...
-c = net:connect(box.cfg.listen)
----
-...
-c.space.test.index.sk.parts
----
-- - type: unsigned
-    is_nullable: true
-    fieldno: 2
-...
-space:drop()
----
-...
-space = box.schema.create_space('test')
----
-...
-c:close()
----
-...
-box.schema.user.grant('guest', 'read', 'space', 'test')
----
-...
-c = net:connect(box.cfg.listen)
----
-...
-box.internal.collation.create('test', 'ICU', 'ru-RU')
----
-...
-collation_id = box.internal.collation.id_by_name('test')
----
-...
-_ = space:create_index('sk', { type = 'tree', parts = {{1, 'str', collation = 'test'}}, unique = true })
----
-...
-c:reload_schema()
----
-...
-parts = c.space.test.index.sk.parts
----
-...
-#parts == 1
----
-- true
-...
-parts[1].fieldno == 1
----
-- true
-...
-parts[1].type == 'string'
----
-- true
-...
-parts[1].is_nullable == false
----
-- true
-...
-if _TARANTOOL >= '2.2.1' then                    \
-    return parts[1].collation == 'test'          \
-else                                             \
-    return parts[1].collation_id == collation_id \
-end
----
-- true
-...
-c:close()
----
-...
-box.internal.collation.drop('test')
----
-...
-space:drop()
----
-...
-c.state
----
-- closed
-...
-c = nil
----
-...
---
--- gh-3107: fiber-async netbox.
---
-cond = nil
----
-...
-box.schema.func.create('long_function')
----
-...
-box.schema.user.grant('guest', 'execute', 'function', 'long_function')
----
-...
-function long_function(...) cond = fiber.cond() cond:wait() return ... end
----
-...
-function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
----
-...
-s = box.schema.create_space('test')
----
-...
-pk = s:create_index('pk')
----
-...
-s:replace{1}
----
-- [1]
-...
-s:replace{2}
----
-- [2]
-...
-s:replace{3}
----
-- [3]
-...
-s:replace{4}
----
-- [4]
-...
-c = net:connect(box.cfg.listen)
----
-...
---
--- Check long connections, multiple wait_result().
---
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
----
-...
-future:result()
----
-- null
-- Response is not ready
-...
-future:is_ready()
----
-- false
-...
-future:wait_result(0.01) -- Must fail on timeout.
----
-- null
-- Timeout exceeded
-...
-finalize_long()
----
-...
-ret = future:wait_result(100)
----
-...
-future:is_ready()
----
-- true
-...
--- Any timeout is ok - response is received already.
-future:wait_result(0)
----
-- [1, 2, 3]
-...
-future:wait_result(0.01)
----
-- [1, 2, 3]
-...
-ret
----
-- [1, 2, 3]
-...
-_, err = pcall(future.wait_result, future, true)
----
-...
-err:find('Usage') ~= nil
----
-- true
-...
-_, err = pcall(future.wait_result, future, '100')
----
-...
-err:find('Usage') ~= nil
----
-- true
-...
---
--- Check infinity timeout.
---
-ret = nil
----
-...
-_ = fiber.create(function() ret = c:call('long_function', {1, 2, 3}, {is_async = true}):wait_result() end)
----
-...
-finalize_long()
----
-...
-while not ret do fiber.sleep(0.01) end
----
-...
-ret
----
-- [1, 2, 3]
-...
-c:close()
----
-...
-box.schema.user.grant('guest', 'execute', 'universe')
----
-...
-c = net:connect(box.cfg.listen)
----
-...
-future = c:eval('return long_function(...)', {1, 2, 3}, {is_async = true})
----
-...
-future:result()
----
-- null
-- Response is not ready
-...
-future:wait_result(0.01) -- Must fail on timeout.
----
-- null
-- Timeout exceeded
-...
-finalize_long()
----
-...
-future:wait_result(100)
----
-- [1, 2, 3]
-...
-c:close()
----
-...
---
--- Check that is_async does not work on a closed connection.
---
-c:call('any_func', {}, {is_async = true})
----
-- error: Connection closed
-...
-box.schema.user.revoke('guest', 'execute', 'universe')
----
-...
-c = net:connect(box.cfg.listen)
----
-...
---
--- Ensure the request is garbage collected both if is not used and
--- if is.
---
-gc_test = setmetatable({}, {__mode = 'v'})
----
-...
-gc_test.future = c:call('long_function', {1, 2, 3}, {is_async = true})
----
-...
-gc_test.future ~= nil
----
-- true
-...
-collectgarbage()
----
-- 0
-...
-gc_test
----
-- []
-...
-finalize_long()
----
-...
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
----
-...
-collectgarbage()
----
-- 0
-...
-future ~= nil
----
-- true
-...
-finalize_long()
----
-...
-future:wait_result(1000)
----
-- [1, 2, 3]
-...
-collectgarbage()
----
-- 0
-...
-future ~= nil
----
-- true
-...
-gc_test.future = future
----
-...
-future = nil
----
-...
-collectgarbage()
----
-- 0
-...
-gc_test
----
-- []
-...
---
--- Ensure a request can be finalized from non-caller fibers.
---
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
----
-...
-ret = {}
----
-...
-count = 0
----
-...
-for i = 1, 10 do fiber.create(function() ret[i] = future:wait_result(1000) count = count + 1 end) end
----
-...
-future:wait_result(0.01) -- Must fail on timeout.
----
-- null
-- Timeout exceeded
-...
-finalize_long()
----
-...
-while count ~= 10 do fiber.sleep(0.1) end
----
-...
-ret
----
-- - &0 [1, 2, 3]
-  - *0
-  - *0
-  - *0
-  - *0
-  - *0
-  - *0
-  - *0
-  - *0
-  - *0
-...
---
--- Test space methods.
---
-c:close()
----
-...
-box.schema.user.grant('guest', 'read,write', 'space', 'test')
----
-...
-c = net:connect(box.cfg.listen)
----
-...
-future = c.space.test:select({1}, {is_async = true})
----
-...
-ret = future:wait_result(100)
----
-...
-ret
----
-- - [1]
-...
-type(ret[1])
----
-- cdata
-...
-future = c.space.test:insert({5}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- [5]
-...
-s:get{5}
----
-- [5]
-...
-future = c.space.test:replace({6}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- [6]
-...
-s:get{6}
----
-- [6]
-...
-future = c.space.test:delete({6}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- [6]
-...
-s:get{6}
----
-...
-future = c.space.test:update({5}, {{'=', 2, 5}}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- [5, 5]
-...
-s:get{5}
----
-- [5, 5]
-...
-future = c.space.test:upsert({5}, {{'=', 2, 6}}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- null
-...
-s:get{5}
----
-- [5, 6]
-...
-future = c.space.test:get({5}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- [5, 6]
-...
---
--- Test index methods.
---
-future = c.space.test.index.pk:select({1}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- - [1]
-...
-future = c.space.test.index.pk:get({2}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- [2]
-...
-future = c.space.test.index.pk:min({}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- [1]
-...
-future = c.space.test.index.pk:max({}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- [5, 6]
-...
-c:close()
----
-...
-box.schema.user.grant('guest', 'execute', 'universe')
----
-...
-c = net:connect(box.cfg.listen)
----
-...
-future = c.space.test.index.pk:count({3}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- 1
-...
-c:close()
----
-...
-box.schema.user.revoke('guest', 'execute', 'universe')
----
-...
-c = net:connect(box.cfg.listen)
----
-...
-future = c.space.test.index.pk:delete({3}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- [3]
-...
-s:get{3}
----
-...
-future = c.space.test.index.pk:update({4}, {{'=', 2, 6}}, {is_async = true})
----
-...
-future:wait_result(100)
----
-- [4, 6]
-...
-s:get{4}
----
-- [4, 6]
-...
---
--- Test async errors.
---
-future = c.space.test:insert({1}, {is_async = true})
----
-...
-future:wait_result()
----
-- null
-- Duplicate key exists in unique index 'pk' in space 'test'
-...
-future:result()
----
-- null
-- Duplicate key exists in unique index 'pk' in space 'test'
-...
---
--- Test discard.
---
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
----
-...
-future:discard()
----
-...
-finalize_long()
----
-...
-future:result()
----
-- null
-- Response is discarded
-...
-future:wait_result(100)
----
-- null
-- Response is discarded
-...
---
--- Test closed connection.
---
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
----
-...
-finalize_long()
----
-...
-future:wait_result(100)
----
-- [1, 2, 3]
-...
-future2 = c:call('long_function', {1, 2, 3}, {is_async = true})
----
-...
-c:close()
----
-...
-future2:wait_result(100)
----
-- null
-- Connection closed
-...
-future2:result()
----
-- null
-- Connection closed
-...
-future2:discard()
----
-...
--- Already successful result must be available.
-future:wait_result(100)
----
-- [1, 2, 3]
-...
-future:result()
----
-- [1, 2, 3]
-...
-future:is_ready()
----
-- true
-...
-finalize_long()
----
-...
---
--- Test reconnect.
---
-c = net:connect(box.cfg.listen, {reconnect_after = 0.01})
----
-...
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
----
-...
-_ = c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80')
----
-...
-while not c:is_connected() do fiber.sleep(0.01) end
----
-...
-finalize_long()
----
-...
-future:wait_result(100)
----
-- null
-- Peer closed
-...
-future:result()
----
-- null
-- Peer closed
-...
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
----
-...
-finalize_long()
----
-...
-future:wait_result(100)
----
-- [1, 2, 3]
-...
---
--- Test raw response getting.
---
-ibuf = require('buffer').ibuf()
----
-...
-future = c:call('long_function', {1, 2, 3}, {is_async = true, buffer = ibuf})
----
-...
-finalize_long()
----
-...
-future:wait_result(100)
----
-- 10
-...
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
----
-...
-result
----
-- {48: [1, 2, 3]}
-...
-box.schema.func.drop('long_function')
----
-...
---
--- Test async schema version change.
---
-function change_schema(i) local tmp = box.schema.create_space('test'..i) return 'ok' end
----
-...
-box.schema.func.create('change_schema')
----
-...
-box.schema.user.grant('guest', 'execute', 'function', 'change_schema')
----
-...
-box.schema.user.grant('guest', 'write', 'space', '_schema')
----
-...
-box.schema.user.grant('guest', 'read,write', 'space', '_space')
----
-...
-box.schema.user.grant('guest', 'create', 'space')
----
-...
-future1 = c:call('change_schema', {'1'}, {is_async = true})
----
-...
-future2 = c:call('change_schema', {'2'}, {is_async = true})
----
-...
-future3 = c:call('change_schema', {'3'}, {is_async = true})
----
-...
-future1:wait_result()
----
-- ['ok']
-...
-future2:wait_result()
----
-- ['ok']
-...
-future3:wait_result()
----
-- ['ok']
-...
-c:close()
----
-...
-s:drop()
----
-...
-box.space.test1:drop()
----
-...
-box.space.test2:drop()
----
-...
-box.space.test3:drop()
----
-...
-box.schema.func.drop('change_schema')
----
-...
---
--- gh-2978: field names for tuples received from netbox.
---
-_ = box.schema.create_space("named", {format = {{name = "id"}, {name="abc"}}})
----
-...
-_ = box.space.named:create_index('id', {parts = {{1, 'unsigned'}}})
----
-...
-box.space.named:insert({1, 1})
----
-- [1, 1]
-...
-box.schema.user.grant('guest', 'read, write, execute', 'space')
----
-...
-cn = net.connect(box.cfg.listen)
----
-...
-s = cn.space.named
----
-...
-s:get{1}.id
----
-- 1
-...
-s:get{1}:tomap()
----
-- 1: 1
-  2: 1
-  abc: 1
-  id: 1
-...
-s:insert{2,3}:tomap()
----
-- 1: 2
-  2: 3
-  abc: 3
-  id: 2
-...
-s:replace{2,14}:tomap()
----
-- 1: 2
-  2: 14
-  abc: 14
-  id: 2
-...
-s:update(1, {{'+', 2, 10}}):tomap()
----
-- 1: 1
-  2: 11
-  abc: 11
-  id: 1
-...
-s:select()[1]:tomap()
----
-- 1: 1
-  2: 11
-  abc: 11
-  id: 1
-...
-s:delete({2}):tomap()
----
-- 1: 2
-  2: 14
-  abc: 14
-  id: 2
-...
--- Check that formats changes after reload.
-box.space.named:format({{name = "id2"}, {name="abc2"}})
----
-...
-s:select()[1]:tomap()
----
-- 1: 1
-  2: 11
-  abc: 11
-  id: 1
-...
-cn:reload_schema()
----
-...
-s:select()[1]:tomap()
----
-- 1: 1
-  2: 11
-  id2: 1
-  abc2: 11
-...
-cn:close()
----
-...
-box.space.named:drop()
----
-...
-box.schema.user.revoke('guest', 'read, write, execute', 'space')
----
-...
---
--- gh-3400: long-poll input discard must not touch event loop of
--- a closed connection.
---
-function long() fiber.yield() return 100 end
----
-...
-c = net.connect(box.cfg.listen)
----
-...
-c:ping()
----
-- true
-...
--- Create batch of two requests. First request is sent to TX
--- thread, second one terminates connection. The preceeding
--- request discards input, and this operation must not trigger
--- new attempts to read any data - the connection is closed
--- already.
---
-f = fiber.create(c._transport.perform_request, nil, nil, false, 'call_17', nil, nil, nil, 'long', {}) c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80')
----
-...
-while f:status() ~= 'dead' do fiber.sleep(0.01) end
----
-...
-c:close()
----
-...
---
--- gh-3464: iproto hangs in 100% CPU when too big packet size
--- is received due to size_t overflow.
---
-c = net:connect(box.cfg.listen)
----
-...
-data = msgpack.encode(18400000000000000000)..'aaaaaaa'
----
-...
-c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, data)
----
-- null
-- Peer closed
-...
-c:close()
----
-...
-test_run:grep_log('default', 'too big packet size in the header') ~= nil
----
-- true
-...
---
--- gh-3629: netbox leaks when a connection is closed deliberately
--- and it has non-finished requests.
---
-ready = false
----
-...
-ok = nil
----
-...
-err = nil
----
-...
-c = net:connect(box.cfg.listen)
----
-...
-function do_long() while not ready do fiber.sleep(0.01) end end
----
-...
-box.schema.func.create('do_long')
----
-...
-box.schema.user.grant('guest', 'execute', 'function', 'do_long')
----
-...
-f = fiber.create(function() ok, err = pcall(c.call, c, 'do_long') end)
----
-...
-while f:status() ~= 'suspended' do fiber.sleep(0.01) end
----
-...
-c:close()
----
-...
-ready = true
----
-...
-while not err do fiber.sleep(0.01) end
----
-...
-ok, err
----
-- false
-- Connection closed
-...
---
--- gh-3856: wait_connected = false is ignored.
---
-c = net.connect('8.8.8.8:123456', {wait_connected = false})
----
-...
-c
----
-- opts:
-    wait_connected: false
-  host: 8.8.8.8
-  state: initial
-  port: '123456'
-...
-c:close()
----
-...
-box.schema.func.drop('do_long')
----
-...
-box.schema.user.revoke('guest', 'write', 'space', '_schema')
----
-...
-box.schema.user.revoke('guest', 'read,write', 'space', '_space')
----
-...
-box.schema.user.revoke('guest', 'create', 'space')
----
-...
---
--- gh-3958 updating box.cfg.readahead doesn't affect existing connections.
---
-readahead = box.cfg.readahead
----
-...
-box.cfg{readahead = 128}
----
-...
-s = box.schema.space.create("test")
----
-...
-_ = s:create_index("pk")
----
-...
-box.schema.user.grant("guest", "read,write", "space", "test")
----
-...
--- connection is created with small readahead value,
--- make sure it is updated if box.cfg.readahead is changed.
-c = net.connect(box.cfg.listen)
----
-...
-box.cfg{readahead = 100 * 1024}
----
-...
-box.error.injection.set("ERRINJ_WAL_DELAY", true)
----
-- ok
-...
-pad = string.rep('x', 8192)
----
-...
-for i = 1, 5 do c.space.test:replace({i, pad}, {is_async = true}) end
----
-...
-box.error.injection.set("ERRINJ_WAL_DELAY", false)
----
-- ok
-...
-test_run:wait_log('default', 'readahead limit is reached', 1024, 0.1)
----
-...
-s:drop()
----
-...
-box.cfg{readahead = readahead}
----
-...
---
--- related to gh-4040: log corrupted rows
---
-log_level = box.cfg.log_level
----
-...
-box.cfg{log_level=6}
----
-...
-sock = socket.tcp_connect(LISTEN.host, LISTEN.service)
----
-...
-sock:read(9)
----
-- Tarantool
-...
--- we need to have a packet with correctly encoded length,
--- so that it bypasses iproto length check, but cannot be
--- decoded in xrow_header_decode
--- 0x3C = 60, sha1 digest is 20 bytes long
-data = string.fromhex('3C'..string.rep(require('digest').sha1_hex('bcde'), 3))
----
-...
-sock:write(data)
----
-- 61
-...
-sock:close()
----
-- true
-...
-test_run:wait_log('default', 'Got a corrupted row.*', nil, 10)
----
-- 'Got a corrupted row:'
-...
-test_run:wait_log('default', '00000000:.*', nil, 10)
----
-- '00000000: A3 02 D6 5A E4 D9 E7 68 A1 53 8D 53 60 5F 20 3F '
-...
-test_run:wait_log('default', '00000010:.*', nil, 10)
----
-- '00000010: D8 E2 D6 E2 A3 02 D6 5A E4 D9 E7 68 A1 53 8D 53 '
-...
-test_run:wait_log('default', '00000020:.*', nil, 10)
----
-- '00000020: 60 5F 20 3F D8 E2 D6 E2 A3 02 D6 5A E4 D9 E7 68 '
-...
-test_run:wait_log('default', '00000030:.*', nil, 10)
----
-- '00000030: A1 53 8D 53 60 5F 20 3F D8 E2 D6 E2 '
-...
--- we expect nothing below, so don't wait
-test_run:grep_log('default', '00000040:.*')
----
-- null
-...
-box.cfg{log_level=log_level}
----
-...
diff --git a/test/box/net.box.test.lua b/test/box/net.box.test.lua
deleted file mode 100644
index 8e65ff470..000000000
--- a/test/box/net.box.test.lua
+++ /dev/null
@@ -1,1585 +0,0 @@
-remote = require 'net.box'
-fiber = require 'fiber'
-log = require 'log'
-msgpack = require 'msgpack'
-env = require('test_run')
-test_run = env.new()
-test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '")
-
-test_run:cmd("setopt delimiter ';'")
-function x_select(cn, space_id, index_id, iterator, offset, limit, key, opts)
-    local ret = cn:_request('select', opts, nil, space_id, index_id, iterator,
-                            offset, limit, key)
-    return ret
-end
-function x_fatal(cn) cn._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80') end
-test_run:cmd("setopt delimiter ''");
-
-LISTEN = require('uri').parse(box.cfg.listen)
-space = box.schema.space.create('net_box_test_space')
-index = space:create_index('primary', { type = 'tree' })
-
--- low level connection
-log.info("create connection")
-cn = remote.connect(LISTEN.host, LISTEN.service)
-log.info("state is %s", cn.state)
-
-cn:ping()
-log.info("ping is done")
-cn:ping()
-log.info("ping is done")
-
-
-cn:ping()
-
-
--- check permissions
-cn:call('unexists_procedure')
-function test_foo(a,b,c) return { {{ [a] = 1 }}, {{ [b] = 2 }}, c } end
-cn:call('test_foo', {'a', 'b', 'c'})
-cn:eval('return 2+2')
-cn:close()
--- connect and call without usage access
-box.schema.user.grant('guest','execute','universe')
-box.schema.user.revoke('guest','usage','universe')
-box.session.su("guest")
-cn = remote.connect(LISTEN.host, LISTEN.service)
-cn:call('test_foo', {'a', 'b', 'c'})
-box.session.su("admin")
-box.schema.user.grant('guest','usage','universe')
-cn:close()
-cn = remote.connect(box.cfg.listen)
-
-cn:call('unexists_procedure')
-cn:call('test_foo', {'a', 'b', 'c'})
-cn:call(nil, {'a', 'b', 'c'})
-cn:eval('return 2+2')
-cn:eval('return 1, 2, 3')
-cn:eval('return ...', {1, 2, 3})
-cn:eval('return { k = "v1" }, true, {  xx = 10, yy = 15 }, nil')
-cn:eval('return nil')
-cn:eval('return')
-cn:eval('error("exception")')
-cn:eval('box.error(0)')
-cn:eval('!invalid expression')
-
--- box.commit() missing at return of CALL/EVAL
-function no_commit() box.begin() fiber.sleep(0.001) end
-cn:call('no_commit')
-cn:eval('no_commit()')
-
-remote.self:eval('return 1+1, 2+2')
-remote.self:eval('return')
-remote.self:eval('error("exception")')
-remote.self:eval('box.error(0)')
-remote.self:eval('!invalid expression')
-
-box.schema.user.revoke('guest', 'execute', 'universe')
-
---
--- gh-822: net.box.call should roll back local transaction on error
---
-
-_ = box.schema.space.create('gh822')
-_ = box.space.gh822:create_index('primary')
-
-test_run:cmd("setopt delimiter ';'")
-
--- rollback on invalid function
-function rollback_on_invalid_function()
-    box.begin()
-    box.space.gh822:insert{1, "netbox_test"}
-    pcall(remote.self.call, remote.self, 'invalid_function')
-    return box.space.gh822:get(1) == nil
-end;
-rollback_on_invalid_function();
-
--- rollback on call error
-function test_error() error('Some error') end;
-function rollback_on_call_error()
-    box.begin()
-    box.space.gh822:insert{1, "netbox_test"}
-    pcall(remote.self.call, remote.self, 'test_error')
-    return box.space.gh822:get(1) == nil
-end;
-rollback_on_call_error();
-
--- rollback on eval
-function rollback_on_eval_error()
-    box.begin()
-    box.space.gh822:insert{1, "netbox_test"}
-    pcall(remote.self.eval, remote.self, "error('Some error')")
-    return box.space.gh822:get(1) == nil
-end;
-rollback_on_eval_error();
-
-test_run:cmd("setopt delimiter ''");
-box.space.gh822:drop()
-
-box.schema.user.grant('guest', 'read,write', 'space', 'net_box_test_space')
-box.schema.user.grant('guest', 'execute', 'universe')
-
-cn:close()
-cn = remote.connect(box.cfg.listen)
-
-x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 0xFFFFFFFF, 123)
-space:insert{123, 345}
-x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 0, 123)
-x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 1, 123)
-x_select(cn, space.id, space.index.primary.id, box.index.EQ, 1, 1, 123)
-
-cn.space[space.id]  ~= nil
-cn.space.net_box_test_space ~= nil
-cn.space.net_box_test_space ~= nil
-cn.space.net_box_test_space.index ~= nil
-cn.space.net_box_test_space.index.primary ~= nil
-cn.space.net_box_test_space.index[space.index.primary.id] ~= nil
-
-
-cn.space.net_box_test_space.index.primary:select(123)
-cn.space.net_box_test_space.index.primary:select(123, { limit = 0 })
-cn.space.net_box_test_space.index.primary:select(nil, { limit = 1, })
-cn.space.net_box_test_space:insert{234, 1,2,3}
-cn.space.net_box_test_space:insert{234, 1,2,3}
-cn.space.net_box_test_space.insert{234, 1,2,3}
-
-cn.space.net_box_test_space:replace{354, 1,2,3}
-cn.space.net_box_test_space:replace{354, 1,2,4}
-
-cn.space.net_box_test_space:select{123}
-space:select({123}, { iterator = 'GE' })
-cn.space.net_box_test_space:select({123}, { iterator = 'GE' })
-cn.space.net_box_test_space:select({123}, { iterator = 'GT' })
-cn.space.net_box_test_space:select({123}, { iterator = 'GT', limit = 1 })
-cn.space.net_box_test_space:select({123}, { iterator = 'GT', limit = 1, offset = 1 })
-
-cn.space.net_box_test_space:select{123}
-cn.space.net_box_test_space:update({123}, { { '+', 2, 1 } })
-cn.space.net_box_test_space:update(123, { { '+', 2, 1 } })
-cn.space.net_box_test_space:select{123}
-
-cn.space.net_box_test_space:insert(cn.space.net_box_test_space:get{123}:update{ { '=', 1, 2 } })
-cn.space.net_box_test_space:delete{123}
-cn.space.net_box_test_space:select{2}
-cn.space.net_box_test_space:select({234}, { iterator = 'LT' })
-
-cn.space.net_box_test_space:update({1}, { { '+', 2, 2 } })
-
-cn.space.net_box_test_space:delete{1}
-cn.space.net_box_test_space:delete{2}
-cn.space.net_box_test_space:delete{2}
-
--- test one-based indexing in splice operation (see update.test.lua)
-cn.space.net_box_test_space:replace({10, 'abcde'})
-cn.space.net_box_test_space:update(10,  {{':', 2, 0, 0, '!'}})
-cn.space.net_box_test_space:update(10,  {{':', 2, 1, 0, '('}})
-cn.space.net_box_test_space:update(10,  {{':', 2, 2, 0, '({'}})
-cn.space.net_box_test_space:update(10,  {{':', 2, -1, 0, ')'}})
-cn.space.net_box_test_space:update(10,  {{':', 2, -2, 0, '})'}})
-cn.space.net_box_test_space:delete{10}
-
-cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
--- gh-841: net.box uses incorrect iterator type for select with no arguments
-cn.space.net_box_test_space:select()
-
-cn.space.net_box_test_space.index.primary:min()
-cn.space.net_box_test_space.index.primary:min(354)
-cn.space.net_box_test_space.index.primary:max()
-cn.space.net_box_test_space.index.primary:max(234)
-cn.space.net_box_test_space.index.primary:count()
-cn.space.net_box_test_space.index.primary:count(354)
-
-cn.space.net_box_test_space:get(354)
-
--- reconnects after errors
-
-box.schema.user.revoke('guest', 'execute', 'universe')
-box.schema.func.create('test_foo')
-box.schema.user.grant('guest', 'execute', 'function', 'test_foo')
-
--- -- 1. no reconnect
-x_fatal(cn)
-cn.state
-cn:ping()
-cn:call('test_foo')
-cn:wait_state('active')
-
--- -- 2 reconnect
-cn = remote.connect(LISTEN.host, LISTEN.service, { reconnect_after = .1 })
-cn.space ~= nil
-
-cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
-x_fatal(cn)
-cn:wait_connected()
-cn:wait_state('active')
-cn:wait_state({active=true})
-cn:ping()
-cn.state
-cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
-
-x_fatal(cn)
-x_select(cn, space.id, 0, box.index.ALL, 0, 0xFFFFFFFF, {})
-
-cn.state
-cn:ping()
-
--- -- dot-new-method
-
-cn1 = remote.new(LISTEN.host, LISTEN.service)
-x_select(cn1, space.id, 0, box.index.ALL, 0, 0xFFFFFFF, {})
-cn1:close()
--- -- error while waiting for response
-type(fiber.create(function() fiber.sleep(.5) x_fatal(cn) end))
-function pause() fiber.sleep(10) return true end
-
-box.schema.func.create('pause')
-box.schema.user.grant('guest', 'execute', 'function', 'pause')
-cn:call('pause')
-cn:call('test_foo', {'a', 'b', 'c'})
-box.schema.func.drop('pause')
-
--- call
-remote.self:call('test_foo', {'a', 'b', 'c'})
-cn:call('test_foo', {'a', 'b', 'c'})
-box.schema.func.drop('test_foo')
-
-box.schema.func.create('long_rep')
-box.schema.user.grant('guest', 'execute', 'function', 'long_rep')
-
--- long replies
-function long_rep() return { 1,  string.rep('a', 5000) } end
-res = cn:call('long_rep')
-res[1] == 1
-res[2] == string.rep('a', 5000)
-
-function long_rep() return { 1,  string.rep('a', 50000) } end
-res = cn:call('long_rep')
-res[1] == 1
-res[2] == string.rep('a', 50000)
-
-box.schema.func.drop('long_rep')
-
--- a.b.c.d
-u = '84F7BCFA-079C-46CC-98B4-F0C821BE833E'
-X = {}
-X.X = X
-function X.fn(x,y) return y or x end
-box.schema.user.grant('guest', 'execute', 'universe')
-cn:close()
-cn = remote.connect(LISTEN.host, LISTEN.service)
-cn:call('X.fn', {u})
-cn:call('X.X.X.X.X.X.X.fn', {u})
-cn:call('X.X.X.X:fn', {u})
-box.schema.user.revoke('guest', 'execute', 'universe')
-cn:close()
-
--- auth
-
-cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123', wait_connected = true })
-cn:is_connected()
-cn.error
-cn.state
-
-
-box.schema.user.create('netbox', { password  = 'test' })
-box.schema.user.grant('netbox', 'read,write', 'space', 'net_box_test_space')
-box.schema.user.grant('netbox', 'execute', 'universe')
-cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = 'test' })
-cn.state
-cn.error
-cn:ping()
-
-function ret_after(to) fiber.sleep(to) return {{to}} end
-
-cn:ping({timeout = 1.00})
-cn:ping({timeout = 1e-9})
-cn:ping()
-
-remote_space = cn.space.net_box_test_space
-remote_pk = remote_space.index.primary
-
-remote_space:insert({0}, { timeout = 1.00 })
-remote_space:insert({1}, { timeout = 1e-9 })
-remote_space:insert({2})
-
-remote_space:replace({0}, { timeout = 1e-9 })
-remote_space:replace({1})
-remote_space:replace({2}, { timeout = 1.00 })
-
-remote_space:upsert({3}, {}, { timeout = 1e-9 })
-remote_space:upsert({4}, {})
-remote_space:upsert({5}, {}, { timeout = 1.00 })
-remote_space:upsert({3}, {})
-
-remote_space:update({3}, {}, { timeout = 1e-9 })
-remote_space:update({4}, {})
-remote_space:update({5}, {}, { timeout = 1.00 })
-remote_space:update({3}, {})
-
-remote_pk:update({5}, {}, { timeout = 1e-9 })
-remote_pk:update({4}, {})
-remote_pk:update({3}, {}, { timeout = 1.00 })
-remote_pk:update({5}, {})
-
-remote_space:get({0})
-remote_space:get({1}, { timeout = 1.00 })
-remote_space:get({2}, { timeout = 1e-9 })
-
-remote_pk:get({3}, { timeout = 1e-9 })
-remote_pk:get({4})
-remote_pk:get({5}, { timeout = 1.00 })
-
-remote_space:select({2}, { timeout = 1e-9 })
-remote_space:select({2}, { timeout = 1.00 })
-remote_space:select({2})
-
-remote_pk:select({2}, { timeout = 1.00 })
-remote_pk:select({2}, { timeout = 1e-9 })
-remote_pk:select({2})
-
-remote_space:select({5}, { timeout = 1.00, iterator = 'LE', limit = 5 })
-remote_space:select({5}, { iterator = 'LE', limit = 5})
-remote_space:select({5}, { timeout = 1e-9, iterator = 'LE', limit = 5 })
-
-remote_pk:select({2}, { timeout = 1.00, iterator = 'LE', limit = 5 })
-remote_pk:select({2}, { iterator = 'LE', limit = 5})
-remote_pk:select({2}, { timeout = 1e-9, iterator = 'LE', limit = 5 })
-
-remote_pk:count({2}, { timeout = 1.00})
-remote_pk:count({2}, { timeout = 1e-9})
-remote_pk:count({2})
-
-remote_pk:count({2}, { timeout = 1.00, iterator = 'LE' })
-remote_pk:count({2}, { iterator = 'LE'})
-remote_pk:count({2}, { timeout = 1e-9, iterator = 'LE' })
-
-remote_pk:min(nil, { timeout = 1.00 })
-remote_pk:min(nil, { timeout = 1e-9 })
-remote_pk:min(nil)
-
-remote_pk:min({0}, { timeout = 1e-9 })
-remote_pk:min({1})
-remote_pk:min({2}, { timeout = 1.00 })
-
-remote_pk:max(nil)
-remote_pk:max(nil, { timeout = 1e-9 })
-remote_pk:max(nil, { timeout = 1.00 })
-
-remote_pk:max({0}, { timeout = 1.00 })
-remote_pk:max({1}, { timeout = 1e-9 })
-remote_pk:max({2})
-
---
--- gh-3262: index:count() inconsistent results
---
-test_run:cmd("setopt delimiter ';'")
-
-function do_count_test(min, it)
-    local r1 = remote_pk:count(min, {iterator = it} )
-    local r2 = box.space.net_box_test_space.index.primary:count(min, {iterator = it} )
-    local r3 = remote.self.space.net_box_test_space.index.primary:count(min, {iterator = it} )
-    return r1 == r2 and r2 == r3
-end;
-
-data = remote_pk:select();
-
-for _, v in pairs(data) do
-    local itrs = {'GE', 'GT', 'LE', 'LT' }
-    for _, it in pairs(itrs) do
-        assert(do_count_test(v[0], it) == true)
-    end
-end;
-
-test_run:cmd("setopt delimiter ''");
-
-_ = remote_space:delete({0}, { timeout = 1e-9 })
-_ = remote_pk:delete({0}, { timeout = 1.00 })
-_ = remote_space:delete({1}, { timeout = 1.00 })
-_ = remote_pk:delete({1}, { timeout = 1e-9 })
-_ = remote_space:delete({2}, { timeout = 1e-9 })
-_ = remote_pk:delete({2})
-_ = remote_pk:delete({3})
-_ = remote_pk:delete({4})
-_ = remote_pk:delete({5})
-
-remote_space:get(0)
-remote_space:get(1)
-remote_space:get(2)
-
-remote_space = nil
-
-cn:call('ret_after', {0.01}, { timeout = 1.00 })
-cn:call('ret_after', {1.00}, { timeout = 1e-9 })
-
-cn:eval('return ret_after(...)', {0.01}, { timeout = 1.00 })
-cn:eval('return ret_after(...)', {1.00}, { timeout = 1e-9 })
-
---
--- :timeout()
--- @deprecated since 1.7.4
---
-
-cn:timeout(1).space.net_box_test_space.index.primary:select{234}
-cn:call('ret_after', {.01})
-cn:timeout(1):call('ret_after', {.01})
-cn:timeout(.01):call('ret_after', {1})
-
-cn = remote:timeout(0.0000000001):connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' })
-cn:close()
-cn = remote:timeout(1):connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' })
-
-remote.self:ping()
-remote.self.space.net_box_test_space:select{234}
-remote.self:timeout(123).space.net_box_test_space:select{234}
-remote.self:is_connected()
-remote.self:wait_connected()
-
-cn:close()
--- cleanup database after tests
-space:drop()
-
--- #1545 empty password
-cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'test' })
-cn ~= nil
-cn:close()
-cn = remote.connect(LISTEN.host, LISTEN.service, { password = 'test' })
-cn ~= nil
-cn:close()
-
--- #544 usage for remote[point]method
-cn = remote.connect(LISTEN.host, LISTEN.service)
-
-box.schema.user.grant('guest', 'execute', 'universe')
-cn:close()
-cn = remote.connect(LISTEN.host, LISTEN.service)
-cn:eval('return true')
-cn.eval('return true')
-
-cn.ping()
-
-cn:close()
-
-remote.self:eval('return true')
-remote.self.eval('return true')
-box.schema.user.revoke('guest', 'execute', 'universe')
-
--- uri as the first argument
-uri = string.format('%s:%s@%s:%s', 'netbox', 'test', LISTEN.host, LISTEN.service)
-
-cn = remote.new(uri)
-cn:ping()
-cn:close()
-
-uri = string.format('%s@%s:%s', 'netbox', LISTEN.host, LISTEN.service)
-cn = remote.new(uri)
-cn ~= nil, cn.state, cn.error
-cn:close()
--- don't merge creds from uri & opts
-remote.new(uri, { password = 'test' })
-cn = remote.new(uri, { user = 'netbox', password = 'test' })
-cn:ping()
-cn:close()
-
-box.schema.user.drop('netbox')
-
--- #594: bad argument #1 to 'setmetatable' (table expected, got number)
-box.schema.func.create('dostring')
-box.schema.user.grant('guest', 'execute', 'function', 'dostring')
-test_run:cmd("setopt delimiter ';'")
-function gh594()
-    local cn = remote.connect(box.cfg.listen)
-    local ping = fiber.create(function() cn:ping() end)
-    cn:call('dostring', {'return 2 + 2'})
-    cn:close()
-end;
-test_run:cmd("setopt delimiter ''");
-gh594()
-box.schema.func.drop('dostring')
-
-
--- #636: Reload schema on demand
-sp = box.schema.space.create('test_old')
-_ = sp:create_index('primary')
-sp:insert{1, 2, 3}
-
-box.schema.user.grant('guest', 'read', 'space', 'test_old')
-con = remote.new(box.cfg.listen)
-con:ping()
-con.space.test_old:select{}
-con.space.test == nil
-
-sp = box.schema.space.create('test')
-_ = sp:create_index('primary')
-sp:insert{2, 3, 4}
-
-box.schema.user.grant('guest', 'read', 'space', 'test')
-
-con.space.test == nil
-con:reload_schema()
-con.space.test:select{}
-
-box.space.test:drop()
-box.space.test_old:drop()
-con:close()
-
-name = string.match(arg[0], "([^,]+)%.lua")
-file_log = require('fio').open(name .. '.log', {'O_RDONLY', 'O_NONBLOCK'})
-file_log:seek(0, 'SEEK_END') ~= 0
-
-box.schema.user.grant('guest', 'execute', 'universe')
-test_run:cmd("setopt delimiter ';'")
-
-_ = fiber.create(
-   function()
-         local conn = require('net.box').new(box.cfg.listen)
-         conn:call('no_such_function', {})
-         conn:close()
-   end
-);
-test_run:cmd("setopt delimiter ''");
-test_run:wait_log('default', 'ER_NO_SUCH_PROC', nil, 10)
-box.schema.user.revoke('guest', 'execute', 'universe')
-
---
--- gh-3900: tarantool can be crashed by sending gibberish to a
--- binary socket
---
-socket = require("socket")
-sock = socket.tcp_connect(LISTEN.host, LISTEN.service)
-data = string.fromhex("6783000000000000000000000000000000000000000000800000C8000000000000000000000000000000000000000000FFFF210100373208000000FFFF000055AAEB66486472530D02000000000010A0350001008000001000000000000000000000000000D05700")
-sock:write(data)
-test_run:wait_log('default', 'ER_INVALID_MSGPACK: Invalid MsgPack %- packet body', nil, 10)
-sock:close()
-
--- gh-983 selecting a lot of data crashes the server or hangs the
--- connection
-
--- gh-983 test case: iproto connection selecting a lot of data
-_ = box.schema.space.create('test', { temporary = true })
-_ = box.space.test:create_index('primary', {type = 'TREE', parts = {1,'unsigned'}})
-
-data1k = "aaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhh"
-
-for i = 0,10000 do box.space.test:insert{i, data1k} end
-
-box.schema.user.grant('guest', 'read', 'space', 'test')
-net = require('net.box')
-c = net:connect(box.cfg.listen)
-r = c.space.test:select(nil, {limit=5000})
-box.space.test:drop()
-
--- gh-970 gh-971 UPSERT over network
-_ = box.schema.space.create('test')
-_ = box.space.test:create_index('primary', {type = 'TREE', parts = {1,'unsigned'}})
-_ = box.space.test:create_index('covering', {type = 'TREE', parts = {1,'unsigned',3,'string',2,'unsigned'}})
-_ = box.space.test:insert{1, 2, "string"}
-box.schema.user.grant('guest', 'read,write', 'space', 'test')
-c = net:connect(box.cfg.listen)
-c.space.test:select{}
-c.space.test:upsert({1, 2, 'nothing'}, {{'+', 2, 1}}) -- common update
-c.space.test:select{}
-c.space.test:upsert({2, 4, 'something'}, {{'+', 2, 1}}) -- insert
-c.space.test:select{}
-c.space.test:upsert({2, 4, 'nothing'}, {{'+', 3, 100500}}) -- wrong operation
-c.space.test:select{}
-
--- gh-1729 net.box index metadata incompatible with local metadata
-c.space.test.index.primary.parts
-c.space.test.index.covering.parts
-
-box.space.test:drop()
-
--- CALL vs CALL_16 in connect options
-function echo(...) return ... end
-box.schema.user.grant('guest', 'execute', 'universe')
-c = net.connect(box.cfg.listen)
-c:call('echo', {42})
-c:eval('return echo(...)', {42})
--- invalid arguments
-c:call('echo', 42)
-c:eval('return echo(...)', 42)
-c:close()
-c = net.connect(box.cfg.listen, {call_16 = true})
-c:call('echo', 42)
-c:eval('return echo(...)', 42)
-c:close()
-box.schema.user.revoke('guest', 'execute', 'universe')
-
---
--- gh-2195 export pure msgpack from net.box
---
-
-space = box.schema.space.create('test')
-_ = box.space.test:create_index('primary')
-box.schema.user.grant('guest', 'read,write', 'space', 'test')
-box.schema.user.grant('guest', 'execute', 'universe')
-c = net.connect(box.cfg.listen)
-ibuf = require('buffer').ibuf()
-
-c:ping()
-c.space.test ~= nil
-
-c.space.test:replace({1, 'hello'})
-
--- replace
-c.space.test:replace({2}, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- replace + skip_header
-c.space.test:replace({2}, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- insert
-c.space.test:insert({3}, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- insert + skip_header
-_ = space:delete({3})
-c.space.test:insert({3}, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- update
-c.space.test:update({3}, {}, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-c.space.test.index.primary:update({3}, {}, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- update + skip_header
-c.space.test:update({3}, {}, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-c.space.test.index.primary:update({3}, {}, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- upsert
-c.space.test:upsert({4}, {}, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- upsert + skip_header
-c.space.test:upsert({4}, {}, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- delete
-c.space.test:upsert({4}, {}, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- delete + skip_header
-c.space.test:upsert({4}, {}, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- select
-c.space.test.index.primary:select({3}, {iterator = 'LE', buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- select + skip_header
-c.space.test.index.primary:select({3}, {iterator = 'LE', buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- select
-len = c.space.test:select({}, {buffer = ibuf})
-ibuf.rpos + len == ibuf.wpos
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-ibuf.rpos == ibuf.wpos
-len
-result
-
--- select + skip_header
-len = c.space.test:select({}, {buffer = ibuf, skip_header = true})
-ibuf.rpos + len == ibuf.wpos
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-ibuf.rpos == ibuf.wpos
-len
-result
-
--- call
-c:call("echo", {1, 2, 3}, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-c:call("echo", {}, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-c:call("echo", nil, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- call + skip_header
-c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-c:call("echo", {}, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-c:call("echo", nil, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- eval
-c:eval("echo(...)", {1, 2, 3}, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-c:eval("echo(...)", {}, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-c:eval("echo(...)", nil, {buffer = ibuf})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- eval + skip_header
-c:eval("echo(...)", {1, 2, 3}, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-c:eval("echo(...)", {}, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-c:eval("echo(...)", nil, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- make several request into a buffer with skip_header, then read
--- results
-c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
-c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
-c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
--- unsupported methods
-c.space.test:get({1}, { buffer = ibuf})
-c.space.test.index.primary:min({}, { buffer = ibuf})
-c.space.test.index.primary:max({}, { buffer = ibuf})
-c.space.test.index.primary:count({}, { buffer = ibuf})
-c.space.test.index.primary:get({1}, { buffer = ibuf})
-
--- error handling
-rpos, wpos = ibuf.rpos, ibuf.wpos
-c.space.test:insert({1}, {buffer = ibuf})
-ibuf.rpos == rpos, ibuf.wpos == wpos
-
-ibuf = nil
-c:close()
-space:drop()
-box.schema.user.revoke('guest', 'execute', 'universe')
-
--- gh-1904 net.box hangs in :close() if a fiber was cancelled
--- while blocked in :_wait_state() in :_request()
-options = {user = 'netbox', password = 'badpass', wait_connected = false, reconnect_after = 0.01}
-c = net:new(box.cfg.listen, options)
-f = fiber.create(function() c:call("") end)
-fiber.sleep(0.01)
-f:cancel(); c:close()
-
-box.schema.user.grant('guest', 'read', 'space', '_schema')
-
--- check for on_schema_reload callback
-test_run:cmd("setopt delimiter ';'")
-do
-    local a = 0
-    function osr_cb()
-        a = a + 1
-    end
-    local con = net.new(box.cfg.listen, {
-        wait_connected = false
-    })
-    con:on_schema_reload(osr_cb)
-    con:wait_connected()
-    con.space._schema:select{}
-    box.schema.space.create('misisipi')
-    box.space.misisipi:drop()
-    con.space._schema:select{}
-    con:close()
-    con = nil
-
-    return a
-end;
-do
-    local a = 0
-    function osr_cb()
-        a = a + 1
-    end
-    local con = net.new(box.cfg.listen, {
-        wait_connected = true
-    })
-    con:on_schema_reload(osr_cb)
-    con.space._schema:select{}
-    box.schema.space.create('misisipi')
-    box.space.misisipi:drop()
-    con.space._schema:select{}
-    con:close()
-    con = nil
-
-    return a
-end;
-test_run:cmd("setopt delimiter ''");
-
-box.schema.user.revoke('guest', 'read', 'space', '_schema')
-
--- Tarantool < 1.7.1 compatibility (gh-1533)
-c = net.new(box.cfg.listen)
-c:ping()
-c:close()
-
--- Test for connect_timeout > 0 in netbox connect
-test_run:cmd("setopt delimiter ';'");
-need_stop = false;
-greeting =
-"Tarantool 1.7.3 (Lua console)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" ..
-"type 'help' for interactive help~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
-socket = require('socket');
-srv = socket.tcp_server('localhost', 0, {
-    handler = function(fd)
-        local fiber = require('fiber')
-        while not need_stop do
-            fiber.sleep(0.01)
-        end
-        fd:write(greeting)
-    end
-});
-port = srv:name().port
--- we must get timeout
-nb = net.new('localhost:' .. port, {
-    wait_connected = true, console = true,
-    connect_timeout = 0.1
-});
-nb.error:find('timed out') ~= nil;
-need_stop = true
-nb:close();
--- we must get peer closed
-nb = net.new('localhost:' .. port, {
-    wait_connected = true, console = true,
-    connect_timeout = 0.2
-});
-nb.error ~= "Timeout exceeded";
-nb:close();
-test_run:cmd("setopt delimiter ''");
-srv:close()
-
-test_run:cmd("clear filter")
-
---
--- gh-2402 net.box doesn't support space:format()
---
-
-space = box.schema.space.create('test', {format={{name="id", type="unsigned"}}})
-space ~= nil
-_ = box.space.test:create_index('primary')
-box.schema.user.grant('guest', 'read', 'space', 'test')
-
-c = net.connect(box.cfg.listen)
-
-c:ping()
-c.space.test ~= nil
-
-format = c.space.test:format()
-
-format[1] ~= nil
-format[1].name == "id"
-format[1].type == "unsigned"
-
-c.space.test:format({})
-
---
--- gh-4091: index unique flag is always false.
---
-c.space.test.index.primary.unique
-
-c:close()
-space:drop()
-
---
--- Check that it's possible to get connection object form net.box space
---
-
-space = box.schema.space.create('test', {format={{name="id", type="unsigned"}}})
-space ~= nil
-_ = box.space.test:create_index('primary')
-box.schema.user.grant('guest','read,write,execute','space', 'test')
-
-c = net.connect(box.cfg.listen)
-
-c:ping()
-c.space.test ~= nil
-
-c.space.test.connection == c
-box.schema.user.revoke('guest','read,write,execute','space', 'test')
-c:close()
-
---
--- gh-2642: box.session.type()
---
-
-box.schema.user.grant('guest','execute','universe')
-c = net.connect(box.cfg.listen)
-c:call("box.session.type")
-c:close()
-box.schema.user.revoke('guest', 'execute', 'universe')
-
-
---
--- On_connect/disconnect triggers.
---
-test_run:cmd('create server connecter with script = "box/proxy.lua"')
-test_run:cmd('start server connecter')
-test_run:cmd("set variable connect_to to 'connecter.listen'")
-conn = net.connect(connect_to, { reconnect_after = 0.1 })
-conn.state
-connected_cnt = 0
-disconnected_cnt = 0
-function on_connect() connected_cnt = connected_cnt + 1 end
-function on_disconnect() disconnected_cnt = disconnected_cnt + 1 end
-conn:on_connect(on_connect)
-conn:on_disconnect(on_disconnect)
-test_run:cmd('stop server connecter')
-test_run:cmd('start server connecter')
-while conn.state ~= 'active' do fiber.sleep(0.1) end
-connected_cnt
-old_disconnected_cnt = disconnected_cnt
-disconnected_cnt >= 1
-conn:close()
-disconnected_cnt == old_disconnected_cnt + 1
-test_run:cmd('stop server connecter')
-
---
--- gh-2401 update pseudo objects not replace them
---
-space:drop()
-space = box.schema.space.create('test')
-box.schema.user.grant('guest', 'read', 'space', 'test')
-c = net.connect(box.cfg.listen)
-cspace = c.space.test
-space.index.test_index == nil
-cspace.index.test_index == nil
-_ = space:create_index("test_index", {parts={1, 'string'}})
-c:reload_schema()
-space.index.test_index ~= nil
-cspace.index.test_index ~= nil
-c.space.test.index.test_index ~= nil
-
--- cleanup
-
-space:drop()
-
---
--- gh-946: long polling CALL blocks input
---
-box.schema.func.create('fast_call')
-box.schema.func.create('long_call')
-box.schema.func.create('wait_signal')
-box.schema.user.grant('guest', 'execute', 'function', 'fast_call')
-box.schema.user.grant('guest', 'execute', 'function', 'long_call')
-box.schema.user.grant('guest', 'execute', 'function', 'wait_signal')
-c = net.connect(box.cfg.listen)
-
-N = 100
-
-pad = string.rep('x', 1024)
-
-long_call_cond = fiber.cond()
-long_call_channel = fiber.channel()
-fast_call_channel = fiber.channel()
-
-function fast_call(x) return x end
-function long_call(x) long_call_cond:wait() return x * 2 end
-
-test_run:cmd("setopt delimiter ';'")
-for i = 1, N do
-    fiber.create(function()
-        fast_call_channel:put(c:call('fast_call', {i, pad}))
-    end)
-    fiber.create(function()
-        long_call_channel:put(c:call('long_call', {i, pad}))
-    end)
-end
-test_run:cmd("setopt delimiter ''");
-
-x = 0
-for i = 1, N do x = x + fast_call_channel:get() end
-x
-
-long_call_cond:broadcast()
-
-x = 0
-for i = 1, N do x = x + long_call_channel:get() end
-x
-
---
--- Check that a connection does not leak if there is
--- a long CALL in progress when it is closed.
---
-disconnected = false
-function on_disconnect() disconnected = true end
-
--- Make sure all dangling connections are collected so
--- that on_disconnect trigger isn't called spuriously.
-collectgarbage('collect')
-fiber.sleep(0)
-
-box.session.on_disconnect(on_disconnect) == on_disconnect
-
---
--- gh-3859: on_disconnect is called only after all requests are
--- processed, but should be called right after disconnect and
--- only once.
---
-ch1 = fiber.channel(1)
-ch2 = fiber.channel(1)
-function wait_signal() ch1:put(true) ch2:get() end
-_ = fiber.create(function() c:call('wait_signal') end)
-ch1:get()
-
-c:close()
-fiber.sleep(0)
-while disconnected == false do fiber.sleep(0.01) end
-disconnected -- true
-disconnected = nil
-
-ch2:put(true)
-fiber.sleep(0)
-disconnected -- nil, on_disconnect is not called second time.
-
-box.session.on_disconnect(nil, on_disconnect)
-
-box.schema.func.drop('long_call')
-box.schema.func.drop('fast_call')
-box.schema.func.drop('wait_signal')
---
--- gh-2666: check that netbox.call is not repeated on schema
--- change.
---
-box.schema.user.grant('guest', 'write', 'space', '_space')
-box.schema.user.grant('guest', 'write', 'space', '_schema')
-box.schema.user.grant('guest', 'create', 'universe')
-count = 0
-function create_space(name) count = count + 1 box.schema.create_space(name) return true end
-box.schema.func.create('create_space')
-box.schema.user.grant('guest', 'execute', 'function', 'create_space')
-c = net.connect(box.cfg.listen)
-c:call('create_space', {'test1'})
-count
-c:call('create_space', {'test2'})
-count
-c:call('create_space', {'test3'})
-count
-box.space.test1:drop()
-box.space.test2:drop()
-box.space.test3:drop()
-box.schema.user.revoke('guest', 'write', 'space', '_space')
-box.schema.user.revoke('guest', 'write', 'space', '_schema')
-box.schema.user.revoke('guest', 'create', 'universe')
-c:close()
-box.schema.func.drop('create_space')
-
---
--- gh-3164: netbox connection is not closed and garbage collected
--- ever, if reconnect_after is set.
---
-test_run:cmd('start server connecter')
-test_run:cmd("set variable connect_to to 'connecter.listen'")
-weak = setmetatable({}, {__mode = 'v'})
--- Create strong and weak reference. Weak is valid until strong
--- is valid too.
-strong = net.connect(connect_to, {reconnect_after = 0.1})
-weak.c = strong
-weak.c:ping()
-test_run:cmd('stop server connecter')
-test_run:cmd('cleanup server connecter')
--- Check the connection tries to reconnect at least two times.
--- 'Cannot assign requested address' is the crutch for running the
--- tests in a docker. This error emits instead of
--- 'Connection refused' inside a docker.
-old_log_level = box.cfg.log_level
-box.cfg{log_level = 6}
-log.info(string.rep('a', 1000))
-test_run:cmd("setopt delimiter ';'")
-while test_run:grep_log('default', 'Network is unreachable', 1000) == nil and
-      test_run:grep_log('default', 'Connection refused', 1000) == nil and
-      test_run:grep_log('default', 'Cannot assign requested address', 1000) == nil do
-       fiber.sleep(0.1)
-end;
-log.info(string.rep('a', 1000));
-while test_run:grep_log('default', 'Network is unreachable', 1000) == nil and
-      test_run:grep_log('default', 'Connection refused', 1000) == nil and
-      test_run:grep_log('default', 'Cannot assign requested address', 1000) == nil do
-       fiber.sleep(0.1)
-end;
-test_run:cmd("setopt delimiter ''");
-box.cfg{log_level = old_log_level}
-collectgarbage('collect')
-strong.state
-strong == weak.c
--- Remove single strong reference. Now connection must be garbage
--- collected.
-strong = nil
-collectgarbage('collect')
--- Now weak.c is null, because it was weak reference, and the
--- connection is deleted by 'collect'.
-weak.c
-
---
--- gh-2677: netbox supports console connections, that complicates
--- both console and netbox. It was necessary because before a
--- connection is established, a console does not known is it
--- binary or text protocol, and netbox could not be created from
--- existing socket.
---
-box.schema.user.grant('guest', 'execute', 'universe')
-urilib = require('uri')
-uri = urilib.parse(tostring(box.cfg.listen))
-s, greeting = net.establish_connection(uri.host, uri.service)
-c = net.wrap(s, greeting, uri.host, uri.service, {reconnect_after = 0.01})
-c.state
-
-a = 100
-function kek(args) return {1, 2, 3, args} end
-c:eval('a = 200')
-a
-c:call('kek', {300})
-s = box.schema.create_space('test')
-box.schema.user.grant('guest', 'read,write', 'space', 'test')
-pk = s:create_index('pk')
-c:reload_schema()
-c.space.test:replace{1}
-c.space.test:get{1}
-c.space.test:delete{1}
---
--- Break a connection to test reconnect_after.
---
-_ = c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80')
-while not c:is_connected() do fiber.sleep(0.01) end
-c:ping()
-
-s:drop()
-c:close()
-
---
--- Test a case, when netbox can not connect first time, but
--- reconnect_after is set.
---
-c = net.connect('localhost:33333', {reconnect_after = 0.1, wait_connected = false})
-while c.state ~= 'error_reconnect' do fiber.sleep(0.01) end
-c:close()
-
-box.schema.user.revoke('guest', 'execute', 'universe')
-c.state
-c = nil
-
---
--- gh-3256 net.box is_nullable and collation options output
---
-space = box.schema.create_space('test')
-box.schema.user.grant('guest', 'read', 'space', 'test')
-_ = space:create_index('pk')
-_ = space:create_index('sk', {parts = {{2, 'unsigned', is_nullable = true}}})
-c = net:connect(box.cfg.listen)
-c.space.test.index.sk.parts
-space:drop()
-
-space = box.schema.create_space('test')
-c:close()
-box.schema.user.grant('guest', 'read', 'space', 'test')
-c = net:connect(box.cfg.listen)
-box.internal.collation.create('test', 'ICU', 'ru-RU')
-collation_id = box.internal.collation.id_by_name('test')
-_ = space:create_index('sk', { type = 'tree', parts = {{1, 'str', collation = 'test'}}, unique = true })
-c:reload_schema()
-parts = c.space.test.index.sk.parts
-#parts == 1
-parts[1].fieldno == 1
-parts[1].type == 'string'
-parts[1].is_nullable == false
-if _TARANTOOL >= '2.2.1' then                    \
-    return parts[1].collation == 'test'          \
-else                                             \
-    return parts[1].collation_id == collation_id \
-end
-c:close()
-box.internal.collation.drop('test')
-space:drop()
-c.state
-c = nil
-
---
--- gh-3107: fiber-async netbox.
---
-cond = nil
-box.schema.func.create('long_function')
-box.schema.user.grant('guest', 'execute', 'function', 'long_function')
-function long_function(...) cond = fiber.cond() cond:wait() return ... end
-function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
-s = box.schema.create_space('test')
-pk = s:create_index('pk')
-s:replace{1}
-s:replace{2}
-s:replace{3}
-s:replace{4}
-c = net:connect(box.cfg.listen)
---
--- Check long connections, multiple wait_result().
---
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
-future:result()
-future:is_ready()
-future:wait_result(0.01) -- Must fail on timeout.
-finalize_long()
-ret = future:wait_result(100)
-future:is_ready()
--- Any timeout is ok - response is received already.
-future:wait_result(0)
-future:wait_result(0.01)
-ret
-
-_, err = pcall(future.wait_result, future, true)
-err:find('Usage') ~= nil
-_, err = pcall(future.wait_result, future, '100')
-err:find('Usage') ~= nil
-
---
--- Check infinity timeout.
---
-ret = nil
-_ = fiber.create(function() ret = c:call('long_function', {1, 2, 3}, {is_async = true}):wait_result() end)
-finalize_long()
-while not ret do fiber.sleep(0.01) end
-ret
-c:close()
-box.schema.user.grant('guest', 'execute', 'universe')
-c = net:connect(box.cfg.listen)
-future = c:eval('return long_function(...)', {1, 2, 3}, {is_async = true})
-future:result()
-future:wait_result(0.01) -- Must fail on timeout.
-finalize_long()
-future:wait_result(100)
-
-c:close()
---
--- Check that is_async does not work on a closed connection.
---
-c:call('any_func', {}, {is_async = true})
-
-box.schema.user.revoke('guest', 'execute', 'universe')
-c = net:connect(box.cfg.listen)
-
---
--- Ensure the request is garbage collected both if is not used and
--- if is.
---
-gc_test = setmetatable({}, {__mode = 'v'})
-gc_test.future = c:call('long_function', {1, 2, 3}, {is_async = true})
-gc_test.future ~= nil
-collectgarbage()
-gc_test
-finalize_long()
-
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
-collectgarbage()
-future ~= nil
-finalize_long()
-future:wait_result(1000)
-collectgarbage()
-future ~= nil
-gc_test.future = future
-future = nil
-collectgarbage()
-gc_test
-
---
--- Ensure a request can be finalized from non-caller fibers.
---
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
-ret = {}
-count = 0
-for i = 1, 10 do fiber.create(function() ret[i] = future:wait_result(1000) count = count + 1 end) end
-future:wait_result(0.01) -- Must fail on timeout.
-finalize_long()
-while count ~= 10 do fiber.sleep(0.1) end
-ret
-
---
--- Test space methods.
---
-c:close()
-box.schema.user.grant('guest', 'read,write', 'space', 'test')
-c = net:connect(box.cfg.listen)
-future = c.space.test:select({1}, {is_async = true})
-ret = future:wait_result(100)
-ret
-type(ret[1])
-future = c.space.test:insert({5}, {is_async = true})
-future:wait_result(100)
-s:get{5}
-future = c.space.test:replace({6}, {is_async = true})
-future:wait_result(100)
-s:get{6}
-future = c.space.test:delete({6}, {is_async = true})
-future:wait_result(100)
-s:get{6}
-future = c.space.test:update({5}, {{'=', 2, 5}}, {is_async = true})
-future:wait_result(100)
-s:get{5}
-future = c.space.test:upsert({5}, {{'=', 2, 6}}, {is_async = true})
-future:wait_result(100)
-s:get{5}
-future = c.space.test:get({5}, {is_async = true})
-future:wait_result(100)
-
---
--- Test index methods.
---
-future = c.space.test.index.pk:select({1}, {is_async = true})
-future:wait_result(100)
-future = c.space.test.index.pk:get({2}, {is_async = true})
-future:wait_result(100)
-future = c.space.test.index.pk:min({}, {is_async = true})
-future:wait_result(100)
-future = c.space.test.index.pk:max({}, {is_async = true})
-future:wait_result(100)
-c:close()
-box.schema.user.grant('guest', 'execute', 'universe')
-c = net:connect(box.cfg.listen)
-future = c.space.test.index.pk:count({3}, {is_async = true})
-future:wait_result(100)
-c:close()
-box.schema.user.revoke('guest', 'execute', 'universe')
-c = net:connect(box.cfg.listen)
-future = c.space.test.index.pk:delete({3}, {is_async = true})
-future:wait_result(100)
-s:get{3}
-future = c.space.test.index.pk:update({4}, {{'=', 2, 6}}, {is_async = true})
-future:wait_result(100)
-s:get{4}
-
---
--- Test async errors.
---
-future = c.space.test:insert({1}, {is_async = true})
-future:wait_result()
-future:result()
-
---
--- Test discard.
---
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
-future:discard()
-finalize_long()
-future:result()
-future:wait_result(100)
-
---
--- Test closed connection.
---
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
-finalize_long()
-future:wait_result(100)
-future2 = c:call('long_function', {1, 2, 3}, {is_async = true})
-c:close()
-future2:wait_result(100)
-future2:result()
-future2:discard()
--- Already successful result must be available.
-future:wait_result(100)
-future:result()
-future:is_ready()
-finalize_long()
-
---
--- Test reconnect.
---
-c = net:connect(box.cfg.listen, {reconnect_after = 0.01})
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
-_ = c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80')
-while not c:is_connected() do fiber.sleep(0.01) end
-finalize_long()
-future:wait_result(100)
-future:result()
-future = c:call('long_function', {1, 2, 3}, {is_async = true})
-finalize_long()
-future:wait_result(100)
-
---
--- Test raw response getting.
---
-ibuf = require('buffer').ibuf()
-future = c:call('long_function', {1, 2, 3}, {is_async = true, buffer = ibuf})
-finalize_long()
-future:wait_result(100)
-result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
-result
-
-box.schema.func.drop('long_function')
-
---
--- Test async schema version change.
---
-function change_schema(i) local tmp = box.schema.create_space('test'..i) return 'ok' end
-box.schema.func.create('change_schema')
-box.schema.user.grant('guest', 'execute', 'function', 'change_schema')
-box.schema.user.grant('guest', 'write', 'space', '_schema')
-box.schema.user.grant('guest', 'read,write', 'space', '_space')
-box.schema.user.grant('guest', 'create', 'space')
-future1 = c:call('change_schema', {'1'}, {is_async = true})
-future2 = c:call('change_schema', {'2'}, {is_async = true})
-future3 = c:call('change_schema', {'3'}, {is_async = true})
-future1:wait_result()
-future2:wait_result()
-future3:wait_result()
-
-c:close()
-s:drop()
-box.space.test1:drop()
-box.space.test2:drop()
-box.space.test3:drop()
-box.schema.func.drop('change_schema')
-
---
--- gh-2978: field names for tuples received from netbox.
---
-_ = box.schema.create_space("named", {format = {{name = "id"}, {name="abc"}}})
-_ = box.space.named:create_index('id', {parts = {{1, 'unsigned'}}})
-box.space.named:insert({1, 1})
-box.schema.user.grant('guest', 'read, write, execute', 'space')
-cn = net.connect(box.cfg.listen)
-
-s = cn.space.named
-s:get{1}.id
-s:get{1}:tomap()
-s:insert{2,3}:tomap()
-s:replace{2,14}:tomap()
-s:update(1, {{'+', 2, 10}}):tomap()
-s:select()[1]:tomap()
-s:delete({2}):tomap()
-
--- Check that formats changes after reload.
-box.space.named:format({{name = "id2"}, {name="abc2"}})
-s:select()[1]:tomap()
-cn:reload_schema()
-s:select()[1]:tomap()
-
-cn:close()
-box.space.named:drop()
-box.schema.user.revoke('guest', 'read, write, execute', 'space')
-
---
--- gh-3400: long-poll input discard must not touch event loop of
--- a closed connection.
---
-function long() fiber.yield() return 100 end
-c = net.connect(box.cfg.listen)
-c:ping()
--- Create batch of two requests. First request is sent to TX
--- thread, second one terminates connection. The preceeding
--- request discards input, and this operation must not trigger
--- new attempts to read any data - the connection is closed
--- already.
---
-f = fiber.create(c._transport.perform_request, nil, nil, false, 'call_17', nil, nil, nil, 'long', {}) c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80')
-while f:status() ~= 'dead' do fiber.sleep(0.01) end
-c:close()
-
---
--- gh-3464: iproto hangs in 100% CPU when too big packet size
--- is received due to size_t overflow.
---
-c = net:connect(box.cfg.listen)
-data = msgpack.encode(18400000000000000000)..'aaaaaaa'
-c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, data)
-c:close()
-test_run:grep_log('default', 'too big packet size in the header') ~= nil
-
-
---
--- gh-3629: netbox leaks when a connection is closed deliberately
--- and it has non-finished requests.
---
-ready = false
-ok = nil
-err = nil
-c = net:connect(box.cfg.listen)
-function do_long() while not ready do fiber.sleep(0.01) end end
-box.schema.func.create('do_long')
-box.schema.user.grant('guest', 'execute', 'function', 'do_long')
-f = fiber.create(function() ok, err = pcall(c.call, c, 'do_long') end)
-while f:status() ~= 'suspended' do fiber.sleep(0.01) end
-c:close()
-ready = true
-while not err do fiber.sleep(0.01) end
-ok, err
-
---
--- gh-3856: wait_connected = false is ignored.
---
-c = net.connect('8.8.8.8:123456', {wait_connected = false})
-c
-c:close()
-
-box.schema.func.drop('do_long')
-box.schema.user.revoke('guest', 'write', 'space', '_schema')
-box.schema.user.revoke('guest', 'read,write', 'space', '_space')
-box.schema.user.revoke('guest', 'create', 'space')
-
---
--- gh-3958 updating box.cfg.readahead doesn't affect existing connections.
---
-readahead = box.cfg.readahead
-
-box.cfg{readahead = 128}
-
-s = box.schema.space.create("test")
-_ = s:create_index("pk")
-box.schema.user.grant("guest", "read,write", "space", "test")
-
--- connection is created with small readahead value,
--- make sure it is updated if box.cfg.readahead is changed.
-c = net.connect(box.cfg.listen)
-
-box.cfg{readahead = 100 * 1024}
-
-box.error.injection.set("ERRINJ_WAL_DELAY", true)
-pad = string.rep('x', 8192)
-for i = 1, 5 do c.space.test:replace({i, pad}, {is_async = true}) end
-box.error.injection.set("ERRINJ_WAL_DELAY", false)
-
-test_run:wait_log('default', 'readahead limit is reached', 1024, 0.1)
-
-s:drop()
-box.cfg{readahead = readahead}
-
---
--- related to gh-4040: log corrupted rows
---
-log_level = box.cfg.log_level
-box.cfg{log_level=6}
-sock = socket.tcp_connect(LISTEN.host, LISTEN.service)
-sock:read(9)
--- we need to have a packet with correctly encoded length,
--- so that it bypasses iproto length check, but cannot be
--- decoded in xrow_header_decode
--- 0x3C = 60, sha1 digest is 20 bytes long
-data = string.fromhex('3C'..string.rep(require('digest').sha1_hex('bcde'), 3))
-sock:write(data)
-sock:close()
-
-test_run:wait_log('default', 'Got a corrupted row.*', nil, 10)
-test_run:wait_log('default', '00000000:.*', nil, 10)
-test_run:wait_log('default', '00000010:.*', nil, 10)
-test_run:wait_log('default', '00000020:.*', nil, 10)
-test_run:wait_log('default', '00000030:.*', nil, 10)
--- we expect nothing below, so don't wait
-test_run:grep_log('default', '00000040:.*')
-
-box.cfg{log_level=log_level}
diff --git a/test/box/net.box_bad_argument_gh-594.result b/test/box/net.box_bad_argument_gh-594.result
new file mode 100644
index 000000000..339886eaa
--- /dev/null
+++ b/test/box/net.box_bad_argument_gh-594.result
@@ -0,0 +1,38 @@
+remote = require 'net.box'
+---
+...
+fiber = require 'fiber'
+---
+...
+test_run = require('test_run').new()
+---
+...
+-- #594: bad argument #1 to 'setmetatable' (table expected, got number)
+box.schema.func.create('dostring')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'dostring')
+---
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+function gh594()
+    local cn = remote.connect(box.cfg.listen)
+    local ping = fiber.create(function() cn:ping() end)
+    cn:call('dostring', {'return 2 + 2'})
+    cn:close()
+end;
+---
+...
+test_run:cmd("setopt delimiter ''");
+---
+- true
+...
+gh594()
+---
+...
+box.schema.func.drop('dostring')
+---
+...
diff --git a/test/box/net.box_bad_argument_gh-594.test.lua b/test/box/net.box_bad_argument_gh-594.test.lua
new file mode 100644
index 000000000..65265cbb5
--- /dev/null
+++ b/test/box/net.box_bad_argument_gh-594.test.lua
@@ -0,0 +1,17 @@
+remote = require 'net.box'
+fiber = require 'fiber'
+test_run = require('test_run').new()
+
+-- #594: bad argument #1 to 'setmetatable' (table expected, got number)
+box.schema.func.create('dostring')
+box.schema.user.grant('guest', 'execute', 'function', 'dostring')
+test_run:cmd("setopt delimiter ';'")
+function gh594()
+    local cn = remote.connect(box.cfg.listen)
+    local ping = fiber.create(function() cn:ping() end)
+    cn:call('dostring', {'return 2 + 2'})
+    cn:close()
+end;
+test_run:cmd("setopt delimiter ''");
+gh594()
+box.schema.func.drop('dostring')
diff --git a/test/box/net.box_call_blocks_gh-946.result b/test/box/net.box_call_blocks_gh-946.result
new file mode 100644
index 000000000..40afec416
--- /dev/null
+++ b/test/box/net.box_call_blocks_gh-946.result
@@ -0,0 +1,124 @@
+fiber = require 'fiber'
+---
+...
+test_run = require('test_run').new()
+---
+...
+--space = box.schema.space.create('net_box_test_space')
+--index = space:create_index('primary', { type = 'tree' })
+net = require('net.box')
+---
+...
+socket = require('socket');
+---
+...
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+---
+- true
+...
+--
+-- gh-946: long polling CALL blocks input
+--
+box.schema.func.create('fast_call')
+---
+...
+box.schema.func.create('long_call')
+---
+...
+box.schema.func.create('wait_signal')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'fast_call')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'long_call')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'wait_signal')
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+N = 100
+---
+...
+pad = string.rep('x', 1024)
+---
+...
+long_call_cond = fiber.cond()
+---
+...
+long_call_channel = fiber.channel()
+---
+...
+fast_call_channel = fiber.channel()
+---
+...
+function fast_call(x) return x end
+---
+...
+function long_call(x) long_call_cond:wait() return x * 2 end
+---
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+for i = 1, N do
+    fiber.create(function()
+        fast_call_channel:put(c:call('fast_call', {i, pad}))
+    end)
+    fiber.create(function()
+        long_call_channel:put(c:call('long_call', {i, pad}))
+    end)
+end
+test_run:cmd("setopt delimiter ''");
+---
+...
+x = 0
+---
+...
+for i = 1, N do x = x + fast_call_channel:get() end
+---
+...
+x
+---
+- 5050
+...
+long_call_cond:broadcast()
+---
+...
+x = 0
+---
+...
+for i = 1, N do x = x + long_call_channel:get() end
+---
+...
+x
+---
+- 10100
+...
+--
+-- Check that a connection does not leak if there is
+-- a long CALL in progress when it is closed.
+--
+disconnected = false
+---
+...
+function on_disconnect() disconnected = true end
+---
+...
+-- Make sure all dangling connections are collected so
+-- that on_disconnect trigger isn't called spuriously.
+collectgarbage('collect')
+---
+- 0
+...
+fiber.sleep(0)
+---
+...
+box.session.on_disconnect(on_disconnect) == on_disconnect
+---
+- true
+...
diff --git a/test/box/net.box_call_blocks_gh-946.test.lua b/test/box/net.box_call_blocks_gh-946.test.lua
new file mode 100644
index 000000000..f3cd3f305
--- /dev/null
+++ b/test/box/net.box_call_blocks_gh-946.test.lua
@@ -0,0 +1,67 @@
+fiber = require 'fiber'
+test_run = require('test_run').new()
+
+--space = box.schema.space.create('net_box_test_space')
+--index = space:create_index('primary', { type = 'tree' })
+
+net = require('net.box')
+socket = require('socket');
+
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+
+--
+-- gh-946: long polling CALL blocks input
+--
+box.schema.func.create('fast_call')
+box.schema.func.create('long_call')
+box.schema.func.create('wait_signal')
+box.schema.user.grant('guest', 'execute', 'function', 'fast_call')
+box.schema.user.grant('guest', 'execute', 'function', 'long_call')
+box.schema.user.grant('guest', 'execute', 'function', 'wait_signal')
+c = net.connect(box.cfg.listen)
+
+N = 100
+
+pad = string.rep('x', 1024)
+
+long_call_cond = fiber.cond()
+long_call_channel = fiber.channel()
+fast_call_channel = fiber.channel()
+
+function fast_call(x) return x end
+function long_call(x) long_call_cond:wait() return x * 2 end
+
+test_run:cmd("setopt delimiter ';'")
+for i = 1, N do
+    fiber.create(function()
+        fast_call_channel:put(c:call('fast_call', {i, pad}))
+    end)
+    fiber.create(function()
+        long_call_channel:put(c:call('long_call', {i, pad}))
+    end)
+end
+test_run:cmd("setopt delimiter ''");
+
+x = 0
+for i = 1, N do x = x + fast_call_channel:get() end
+x
+
+long_call_cond:broadcast()
+
+x = 0
+for i = 1, N do x = x + long_call_channel:get() end
+x
+
+--
+-- Check that a connection does not leak if there is
+-- a long CALL in progress when it is closed.
+--
+disconnected = false
+function on_disconnect() disconnected = true end
+
+-- Make sure all dangling connections are collected so
+-- that on_disconnect trigger isn't called spuriously.
+collectgarbage('collect')
+fiber.sleep(0)
+
+box.session.on_disconnect(on_disconnect) == on_disconnect
diff --git a/test/box/net.box_collectgarbage_gh-3107.result b/test/box/net.box_collectgarbage_gh-3107.result
new file mode 100644
index 000000000..240a472de
--- /dev/null
+++ b/test/box/net.box_collectgarbage_gh-3107.result
@@ -0,0 +1,120 @@
+fiber = require 'fiber'
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+---
+...
+box.schema.func.create('long_function')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+---
+...
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+---
+...
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+---
+...
+s = box.schema.create_space('test')
+---
+...
+pk = s:create_index('pk')
+---
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{2}
+---
+- [2]
+...
+s:replace{3}
+---
+- [3]
+...
+s:replace{4}
+---
+- [4]
+...
+c = net:connect(box.cfg.listen)
+---
+...
+--
+-- Ensure the request is garbage collected both if is not used and
+-- if is.
+--
+gc_test = setmetatable({}, {__mode = 'v'})
+---
+...
+gc_test.future = c:call('long_function', {1, 2, 3}, {is_async = true})
+---
+...
+gc_test.future ~= nil
+---
+- true
+...
+collectgarbage()
+---
+- 0
+...
+gc_test
+---
+- []
+...
+finalize_long()
+---
+...
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+---
+...
+collectgarbage()
+---
+- 0
+...
+future ~= nil
+---
+- true
+...
+finalize_long()
+---
+...
+future:wait_result(1000)
+---
+- [1, 2, 3]
+...
+collectgarbage()
+---
+- 0
+...
+future ~= nil
+---
+- true
+...
+gc_test.future = future
+---
+...
+future = nil
+---
+...
+collectgarbage()
+---
+- 0
+...
+gc_test
+---
+- []
+...
+c:close()
+---
+...
+s:drop()
+---
+...
diff --git a/test/box/net.box_collectgarbage_gh-3107.test.lua b/test/box/net.box_collectgarbage_gh-3107.test.lua
new file mode 100644
index 000000000..cfe333757
--- /dev/null
+++ b/test/box/net.box_collectgarbage_gh-3107.test.lua
@@ -0,0 +1,44 @@
+fiber = require 'fiber'
+net = require('net.box')
+
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+box.schema.func.create('long_function')
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+s = box.schema.create_space('test')
+pk = s:create_index('pk')
+s:replace{1}
+s:replace{2}
+s:replace{3}
+s:replace{4}
+c = net:connect(box.cfg.listen)
+
+--
+-- Ensure the request is garbage collected both if is not used and
+-- if is.
+--
+gc_test = setmetatable({}, {__mode = 'v'})
+gc_test.future = c:call('long_function', {1, 2, 3}, {is_async = true})
+gc_test.future ~= nil
+collectgarbage()
+gc_test
+finalize_long()
+
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+collectgarbage()
+future ~= nil
+finalize_long()
+future:wait_result(1000)
+collectgarbage()
+future ~= nil
+gc_test.future = future
+future = nil
+collectgarbage()
+gc_test
+
+c:close()
+s:drop()
diff --git a/test/box/net.box_connect_triggers.result b/test/box/net.box_connect_triggers.result
new file mode 100644
index 000000000..c5b1ef6db
--- /dev/null
+++ b/test/box/net.box_connect_triggers.result
@@ -0,0 +1,82 @@
+fiber = require 'fiber'
+---
+...
+test_run = require('test_run').new()
+---
+...
+net = require('net.box')
+---
+...
+--
+-- On_connect/disconnect triggers.
+--
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+---
+- true
+...
+test_run:cmd('start server connecter')
+---
+- true
+...
+test_run:cmd("set variable connect_to to 'connecter.listen'")
+---
+- true
+...
+conn = net.connect(connect_to, { reconnect_after = 0.1 })
+---
+...
+conn.state
+---
+- active
+...
+connected_cnt = 0
+---
+...
+disconnected_cnt = 0
+---
+...
+function on_connect() connected_cnt = connected_cnt + 1 end
+---
+...
+function on_disconnect() disconnected_cnt = disconnected_cnt + 1 end
+---
+...
+conn:on_connect(on_connect)
+---
+...
+conn:on_disconnect(on_disconnect)
+---
+...
+test_run:cmd('stop server connecter')
+---
+- true
+...
+test_run:cmd('start server connecter')
+---
+- true
+...
+while conn.state ~= 'active' do fiber.sleep(0.1) end
+---
+...
+connected_cnt
+---
+- 1
+...
+old_disconnected_cnt = disconnected_cnt
+---
+...
+disconnected_cnt >= 1
+---
+- true
+...
+conn:close()
+---
+...
+disconnected_cnt == old_disconnected_cnt + 1
+---
+- true
+...
+test_run:cmd('stop server connecter')
+---
+- true
+...
diff --git a/test/box/net.box_connect_triggers.test.lua b/test/box/net.box_connect_triggers.test.lua
new file mode 100644
index 000000000..86794035e
--- /dev/null
+++ b/test/box/net.box_connect_triggers.test.lua
@@ -0,0 +1,27 @@
+fiber = require 'fiber'
+test_run = require('test_run').new()
+net = require('net.box')
+
+--
+-- On_connect/disconnect triggers.
+--
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+test_run:cmd('start server connecter')
+test_run:cmd("set variable connect_to to 'connecter.listen'")
+conn = net.connect(connect_to, { reconnect_after = 0.1 })
+conn.state
+connected_cnt = 0
+disconnected_cnt = 0
+function on_connect() connected_cnt = connected_cnt + 1 end
+function on_disconnect() disconnected_cnt = disconnected_cnt + 1 end
+conn:on_connect(on_connect)
+conn:on_disconnect(on_disconnect)
+test_run:cmd('stop server connecter')
+test_run:cmd('start server connecter')
+while conn.state ~= 'active' do fiber.sleep(0.1) end
+connected_cnt
+old_disconnected_cnt = disconnected_cnt
+disconnected_cnt >= 1
+conn:close()
+disconnected_cnt == old_disconnected_cnt + 1
+test_run:cmd('stop server connecter')
diff --git a/test/box/net.box_console_connections_gh-2677.result b/test/box/net.box_console_connections_gh-2677.result
new file mode 100644
index 000000000..c9116e5d4
--- /dev/null
+++ b/test/box/net.box_console_connections_gh-2677.result
@@ -0,0 +1,95 @@
+fiber = require 'fiber'
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-2677: netbox supports console connections, that complicates
+-- both console and netbox. It was necessary because before a
+-- connection is established, a console does not known is it
+-- binary or text protocol, and netbox could not be created from
+-- existing socket.
+--
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+urilib = require('uri')
+---
+...
+uri = urilib.parse(tostring(box.cfg.listen))
+---
+...
+s, greeting = net.establish_connection(uri.host, uri.service)
+---
+...
+c = net.wrap(s, greeting, uri.host, uri.service, {reconnect_after = 0.01})
+---
+...
+c.state
+---
+- active
+...
+a = 100
+---
+...
+function kek(args) return {1, 2, 3, args} end
+---
+...
+c:eval('a = 200')
+---
+...
+a
+---
+- 200
+...
+c:call('kek', {300})
+---
+- [1, 2, 3, 300]
+...
+s = box.schema.create_space('test')
+---
+...
+box.schema.user.grant('guest', 'read,write', 'space', 'test')
+---
+...
+pk = s:create_index('pk')
+---
+...
+c:reload_schema()
+---
+...
+c.space.test:replace{1}
+---
+- [1]
+...
+c.space.test:get{1}
+---
+- [1]
+...
+c.space.test:delete{1}
+---
+- [1]
+...
+--
+-- Break a connection to test reconnect_after.
+--
+_ = c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80')
+---
+...
+while not c:is_connected() do fiber.sleep(0.01) end
+---
+...
+c:ping()
+---
+- true
+...
+s:drop()
+---
+...
+c:close()
+---
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
diff --git a/test/box/net.box_console_connections_gh-2677.test.lua b/test/box/net.box_console_connections_gh-2677.test.lua
new file mode 100644
index 000000000..c6c9ea846
--- /dev/null
+++ b/test/box/net.box_console_connections_gh-2677.test.lua
@@ -0,0 +1,39 @@
+fiber = require 'fiber'
+net = require('net.box')
+
+--
+-- gh-2677: netbox supports console connections, that complicates
+-- both console and netbox. It was necessary because before a
+-- connection is established, a console does not known is it
+-- binary or text protocol, and netbox could not be created from
+-- existing socket.
+--
+box.schema.user.grant('guest', 'execute', 'universe')
+urilib = require('uri')
+uri = urilib.parse(tostring(box.cfg.listen))
+s, greeting = net.establish_connection(uri.host, uri.service)
+c = net.wrap(s, greeting, uri.host, uri.service, {reconnect_after = 0.01})
+c.state
+
+a = 100
+function kek(args) return {1, 2, 3, args} end
+c:eval('a = 200')
+a
+c:call('kek', {300})
+s = box.schema.create_space('test')
+box.schema.user.grant('guest', 'read,write', 'space', 'test')
+pk = s:create_index('pk')
+c:reload_schema()
+c.space.test:replace{1}
+c.space.test:get{1}
+c.space.test:delete{1}
+--
+-- Break a connection to test reconnect_after.
+--
+_ = c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80')
+while not c:is_connected() do fiber.sleep(0.01) end
+c:ping()
+
+s:drop()
+c:close()
+box.schema.user.revoke('guest', 'execute', 'universe')
diff --git a/test/box/net.box_count_inconsistent_gh-3262.result b/test/box/net.box_count_inconsistent_gh-3262.result
new file mode 100644
index 000000000..c77677625
--- /dev/null
+++ b/test/box/net.box_count_inconsistent_gh-3262.result
@@ -0,0 +1,488 @@
+remote = require 'net.box'
+---
+...
+fiber = require 'fiber'
+---
+...
+test_run = require('test_run').new()
+---
+...
+LISTEN = require('uri').parse(box.cfg.listen)
+---
+...
+space = box.schema.space.create('net_box_test_space')
+---
+...
+index = space:create_index('primary', { type = 'tree' })
+---
+...
+box.schema.user.grant('guest', 'read,write', 'space', 'net_box_test_space')
+---
+...
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+cn = remote.connect(box.cfg.listen)
+---
+...
+cn.space[space.id]  ~= nil
+---
+- true
+...
+cn.space.net_box_test_space ~= nil
+---
+- true
+...
+cn.space.net_box_test_space ~= nil
+---
+- true
+...
+cn.space.net_box_test_space.index ~= nil
+---
+- true
+...
+cn.space.net_box_test_space.index.primary ~= nil
+---
+- true
+...
+cn.space.net_box_test_space.index[space.index.primary.id] ~= nil
+---
+- true
+...
+cn.space.net_box_test_space:insert{234, 1,2,3}
+---
+- [234, 1, 2, 3]
+...
+cn.space.net_box_test_space:replace{354, 1,2,4}
+---
+- [354, 1, 2, 4]
+...
+cn.space.net_box_test_space.index.primary:min(354)
+---
+- [354, 1, 2, 4]
+...
+cn.space.net_box_test_space.index.primary:max(234)
+---
+- [234, 1, 2, 3]
+...
+cn.space.net_box_test_space.index.primary:count(354)
+---
+- 1
+...
+box.schema.user.create('netbox', { password  = 'test' })
+---
+...
+box.schema.user.grant('netbox', 'read,write', 'space', 'net_box_test_space')
+---
+...
+box.schema.user.grant('netbox', 'execute', 'universe')
+---
+...
+cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = 'test' })
+---
+...
+cn.state
+---
+- active
+...
+cn.error
+---
+- null
+...
+cn:ping()
+---
+- true
+...
+function ret_after(to) fiber.sleep(to) return {{to}} end
+---
+...
+cn:ping({timeout = 1.00})
+---
+- true
+...
+cn:ping({timeout = 1e-9})
+---
+- false
+...
+cn:ping()
+---
+- true
+...
+remote_space = cn.space.net_box_test_space
+---
+...
+remote_pk = remote_space.index.primary
+---
+...
+remote_space:insert({0}, { timeout = 1.00 })
+---
+- [0]
+...
+remote_space:insert({1}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_space:insert({2})
+---
+- [2]
+...
+remote_space:replace({0}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_space:replace({1})
+---
+- [1]
+...
+remote_space:replace({2}, { timeout = 1.00 })
+---
+- [2]
+...
+remote_space:upsert({3}, {}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_space:upsert({4}, {})
+---
+...
+remote_space:upsert({5}, {}, { timeout = 1.00 })
+---
+...
+remote_space:upsert({3}, {})
+---
+...
+remote_space:update({3}, {}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_space:update({4}, {})
+---
+- [4]
+...
+remote_space:update({5}, {}, { timeout = 1.00 })
+---
+- [5]
+...
+remote_space:update({3}, {})
+---
+- [3]
+...
+remote_pk:update({5}, {}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_pk:update({4}, {})
+---
+- [4]
+...
+remote_pk:update({3}, {}, { timeout = 1.00 })
+---
+- [3]
+...
+remote_pk:update({5}, {})
+---
+- [5]
+...
+remote_space:get({0})
+---
+- [0]
+...
+remote_space:get({1}, { timeout = 1.00 })
+---
+- [1]
+...
+remote_space:get({2}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_pk:get({3}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_pk:get({4})
+---
+- [4]
+...
+remote_pk:get({5}, { timeout = 1.00 })
+---
+- [5]
+...
+remote_space:select({2}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_space:select({2}, { timeout = 1.00 })
+---
+- - [2]
+...
+remote_space:select({2})
+---
+- - [2]
+...
+remote_pk:select({2}, { timeout = 1.00 })
+---
+- - [2]
+...
+remote_pk:select({2}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_pk:select({2})
+---
+- - [2]
+...
+remote_space:select({5}, { timeout = 1.00, iterator = 'LE', limit = 5 })
+---
+- - [5]
+  - [4]
+  - [3]
+  - [2]
+  - [1]
+...
+remote_space:select({5}, { iterator = 'LE', limit = 5})
+---
+- - [5]
+  - [4]
+  - [3]
+  - [2]
+  - [1]
+...
+remote_space:select({5}, { timeout = 1e-9, iterator = 'LE', limit = 5 })
+---
+- error: Timeout exceeded
+...
+remote_pk:select({2}, { timeout = 1.00, iterator = 'LE', limit = 5 })
+---
+- - [2]
+  - [1]
+  - [0]
+...
+remote_pk:select({2}, { iterator = 'LE', limit = 5})
+---
+- - [2]
+  - [1]
+  - [0]
+...
+remote_pk:select({2}, { timeout = 1e-9, iterator = 'LE', limit = 5 })
+---
+- error: Timeout exceeded
+...
+remote_pk:count({2}, { timeout = 1.00})
+---
+- 1
+...
+remote_pk:count({2}, { timeout = 1e-9})
+---
+- error: Timeout exceeded
+...
+remote_pk:count({2})
+---
+- 1
+...
+remote_pk:count({2}, { timeout = 1.00, iterator = 'LE' })
+---
+- 3
+...
+remote_pk:count({2}, { iterator = 'LE'})
+---
+- 3
+...
+remote_pk:count({2}, { timeout = 1e-9, iterator = 'LE' })
+---
+- error: Timeout exceeded
+...
+remote_pk:min(nil, { timeout = 1.00 })
+---
+- [0]
+...
+remote_pk:min(nil, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_pk:min(nil)
+---
+- [0]
+...
+remote_pk:min({0}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_pk:min({1})
+---
+- [1]
+...
+remote_pk:min({2}, { timeout = 1.00 })
+---
+- [2]
+...
+remote_pk:max(nil)
+---
+- [354, 1, 2, 4]
+...
+remote_pk:max(nil, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_pk:max(nil, { timeout = 1.00 })
+---
+- [354, 1, 2, 4]
+...
+remote_pk:max({0}, { timeout = 1.00 })
+---
+- [0]
+...
+remote_pk:max({1}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+remote_pk:max({2})
+---
+- [2]
+...
+--
+-- gh-3262: index:count() inconsistent results
+--
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+function do_count_test(min, it)
+    local r1 = remote_pk:count(min, {iterator = it} )
+    local r2 = box.space.net_box_test_space.index.primary:count(min, {iterator = it} )
+    local r3 = remote.self.space.net_box_test_space.index.primary:count(min, {iterator = it} )
+    return r1 == r2 and r2 == r3
+end;
+---
+...
+data = remote_pk:select();
+---
+...
+for _, v in pairs(data) do
+    local itrs = {'GE', 'GT', 'LE', 'LT' }
+    for _, it in pairs(itrs) do
+        assert(do_count_test(v[0], it) == true)
+    end
+end;
+---
+...
+test_run:cmd("setopt delimiter ''");
+---
+- true
+...
+_ = remote_space:delete({0}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+_ = remote_pk:delete({0}, { timeout = 1.00 })
+---
+...
+_ = remote_space:delete({1}, { timeout = 1.00 })
+---
+...
+_ = remote_pk:delete({1}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+_ = remote_space:delete({2}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+_ = remote_pk:delete({2})
+---
+...
+_ = remote_pk:delete({3})
+---
+...
+_ = remote_pk:delete({4})
+---
+...
+_ = remote_pk:delete({5})
+---
+...
+remote_space:get(0)
+---
+...
+remote_space:get(1)
+---
+...
+remote_space:get(2)
+---
+...
+remote_space = nil
+---
+...
+cn:call('ret_after', {0.01}, { timeout = 1.00 })
+---
+- [[0.01]]
+...
+cn:call('ret_after', {1.00}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+cn:eval('return ret_after(...)', {0.01}, { timeout = 1.00 })
+---
+- [[0.01]]
+...
+cn:eval('return ret_after(...)', {1.00}, { timeout = 1e-9 })
+---
+- error: Timeout exceeded
+...
+--
+-- :timeout()
+-- @deprecated since 1.7.4
+--
+cn:timeout(1).space.net_box_test_space.index.primary:select{234}
+---
+- - [234, 1, 2, 3]
+...
+cn:call('ret_after', {.01})
+---
+- [[0.01]]
+...
+cn:timeout(1):call('ret_after', {.01})
+---
+- [[0.01]]
+...
+cn:timeout(.01):call('ret_after', {1})
+---
+- error: Timeout exceeded
+...
+cn = remote:timeout(0.0000000001):connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' })
+---
+...
+cn:close()
+---
+...
+cn = remote:timeout(1):connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' })
+---
+...
+remote.self:ping()
+---
+- true
+...
+remote.self.space.net_box_test_space:select{234}
+---
+- - [234, 1, 2, 3]
+...
+remote.self:timeout(123).space.net_box_test_space:select{234}
+---
+- - [234, 1, 2, 3]
+...
+remote.self:is_connected()
+---
+- true
+...
+remote.self:wait_connected()
+---
+- true
+...
+cn:close()
+---
+...
+-- cleanup database after tests
+space:drop()
+---
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
diff --git a/test/box/net.box_count_inconsistent_gh-3262.test.lua b/test/box/net.box_count_inconsistent_gh-3262.test.lua
new file mode 100644
index 000000000..e84e85cf3
--- /dev/null
+++ b/test/box/net.box_count_inconsistent_gh-3262.test.lua
@@ -0,0 +1,182 @@
+remote = require 'net.box'
+fiber = require 'fiber'
+test_run = require('test_run').new()
+
+LISTEN = require('uri').parse(box.cfg.listen)
+space = box.schema.space.create('net_box_test_space')
+index = space:create_index('primary', { type = 'tree' })
+
+box.schema.user.grant('guest', 'read,write', 'space', 'net_box_test_space')
+box.schema.user.grant('guest', 'execute', 'universe')
+
+cn = remote.connect(box.cfg.listen)
+cn.space[space.id]  ~= nil
+cn.space.net_box_test_space ~= nil
+cn.space.net_box_test_space ~= nil
+cn.space.net_box_test_space.index ~= nil
+cn.space.net_box_test_space.index.primary ~= nil
+cn.space.net_box_test_space.index[space.index.primary.id] ~= nil
+cn.space.net_box_test_space:insert{234, 1,2,3}
+cn.space.net_box_test_space:replace{354, 1,2,4}
+cn.space.net_box_test_space.index.primary:min(354)
+cn.space.net_box_test_space.index.primary:max(234)
+cn.space.net_box_test_space.index.primary:count(354)
+
+box.schema.user.create('netbox', { password  = 'test' })
+box.schema.user.grant('netbox', 'read,write', 'space', 'net_box_test_space')
+box.schema.user.grant('netbox', 'execute', 'universe')
+cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = 'test' })
+cn.state
+cn.error
+cn:ping()
+
+function ret_after(to) fiber.sleep(to) return {{to}} end
+
+cn:ping({timeout = 1.00})
+cn:ping({timeout = 1e-9})
+cn:ping()
+
+remote_space = cn.space.net_box_test_space
+remote_pk = remote_space.index.primary
+
+remote_space:insert({0}, { timeout = 1.00 })
+remote_space:insert({1}, { timeout = 1e-9 })
+remote_space:insert({2})
+
+remote_space:replace({0}, { timeout = 1e-9 })
+remote_space:replace({1})
+remote_space:replace({2}, { timeout = 1.00 })
+
+remote_space:upsert({3}, {}, { timeout = 1e-9 })
+remote_space:upsert({4}, {})
+remote_space:upsert({5}, {}, { timeout = 1.00 })
+remote_space:upsert({3}, {})
+
+remote_space:update({3}, {}, { timeout = 1e-9 })
+remote_space:update({4}, {})
+remote_space:update({5}, {}, { timeout = 1.00 })
+remote_space:update({3}, {})
+
+remote_pk:update({5}, {}, { timeout = 1e-9 })
+remote_pk:update({4}, {})
+remote_pk:update({3}, {}, { timeout = 1.00 })
+remote_pk:update({5}, {})
+
+remote_space:get({0})
+remote_space:get({1}, { timeout = 1.00 })
+remote_space:get({2}, { timeout = 1e-9 })
+
+remote_pk:get({3}, { timeout = 1e-9 })
+remote_pk:get({4})
+remote_pk:get({5}, { timeout = 1.00 })
+
+remote_space:select({2}, { timeout = 1e-9 })
+remote_space:select({2}, { timeout = 1.00 })
+remote_space:select({2})
+
+remote_pk:select({2}, { timeout = 1.00 })
+remote_pk:select({2}, { timeout = 1e-9 })
+remote_pk:select({2})
+
+remote_space:select({5}, { timeout = 1.00, iterator = 'LE', limit = 5 })
+remote_space:select({5}, { iterator = 'LE', limit = 5})
+remote_space:select({5}, { timeout = 1e-9, iterator = 'LE', limit = 5 })
+
+remote_pk:select({2}, { timeout = 1.00, iterator = 'LE', limit = 5 })
+remote_pk:select({2}, { iterator = 'LE', limit = 5})
+remote_pk:select({2}, { timeout = 1e-9, iterator = 'LE', limit = 5 })
+
+remote_pk:count({2}, { timeout = 1.00})
+remote_pk:count({2}, { timeout = 1e-9})
+remote_pk:count({2})
+
+remote_pk:count({2}, { timeout = 1.00, iterator = 'LE' })
+remote_pk:count({2}, { iterator = 'LE'})
+remote_pk:count({2}, { timeout = 1e-9, iterator = 'LE' })
+
+remote_pk:min(nil, { timeout = 1.00 })
+remote_pk:min(nil, { timeout = 1e-9 })
+remote_pk:min(nil)
+
+remote_pk:min({0}, { timeout = 1e-9 })
+remote_pk:min({1})
+remote_pk:min({2}, { timeout = 1.00 })
+
+remote_pk:max(nil)
+remote_pk:max(nil, { timeout = 1e-9 })
+remote_pk:max(nil, { timeout = 1.00 })
+
+remote_pk:max({0}, { timeout = 1.00 })
+remote_pk:max({1}, { timeout = 1e-9 })
+remote_pk:max({2})
+
+--
+-- gh-3262: index:count() inconsistent results
+--
+test_run:cmd("setopt delimiter ';'")
+
+function do_count_test(min, it)
+    local r1 = remote_pk:count(min, {iterator = it} )
+    local r2 = box.space.net_box_test_space.index.primary:count(min, {iterator = it} )
+    local r3 = remote.self.space.net_box_test_space.index.primary:count(min, {iterator = it} )
+    return r1 == r2 and r2 == r3
+end;
+
+data = remote_pk:select();
+
+for _, v in pairs(data) do
+    local itrs = {'GE', 'GT', 'LE', 'LT' }
+    for _, it in pairs(itrs) do
+        assert(do_count_test(v[0], it) == true)
+    end
+end;
+
+test_run:cmd("setopt delimiter ''");
+
+_ = remote_space:delete({0}, { timeout = 1e-9 })
+_ = remote_pk:delete({0}, { timeout = 1.00 })
+_ = remote_space:delete({1}, { timeout = 1.00 })
+_ = remote_pk:delete({1}, { timeout = 1e-9 })
+_ = remote_space:delete({2}, { timeout = 1e-9 })
+_ = remote_pk:delete({2})
+_ = remote_pk:delete({3})
+_ = remote_pk:delete({4})
+_ = remote_pk:delete({5})
+
+remote_space:get(0)
+remote_space:get(1)
+remote_space:get(2)
+
+remote_space = nil
+
+cn:call('ret_after', {0.01}, { timeout = 1.00 })
+cn:call('ret_after', {1.00}, { timeout = 1e-9 })
+
+cn:eval('return ret_after(...)', {0.01}, { timeout = 1.00 })
+cn:eval('return ret_after(...)', {1.00}, { timeout = 1e-9 })
+
+--
+-- :timeout()
+-- @deprecated since 1.7.4
+--
+
+cn:timeout(1).space.net_box_test_space.index.primary:select{234}
+cn:call('ret_after', {.01})
+cn:timeout(1):call('ret_after', {.01})
+cn:timeout(.01):call('ret_after', {1})
+
+cn = remote:timeout(0.0000000001):connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' })
+cn:close()
+cn = remote:timeout(1):connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' })
+
+remote.self:ping()
+remote.self.space.net_box_test_space:select{234}
+remote.self:timeout(123).space.net_box_test_space:select{234}
+remote.self:is_connected()
+remote.self:wait_connected()
+
+cn:close()
+-- cleanup database after tests
+space:drop()
+
+box.schema.user.revoke('guest', 'execute', 'universe')
diff --git a/test/box/net.box_discard_gh-3107.result b/test/box/net.box_discard_gh-3107.result
new file mode 100644
index 000000000..3498c9d5a
--- /dev/null
+++ b/test/box/net.box_discard_gh-3107.result
@@ -0,0 +1,119 @@
+fiber = require 'fiber'
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+---
+...
+box.schema.func.create('long_function')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+---
+...
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+---
+...
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+---
+...
+s = box.schema.create_space('test')
+---
+...
+pk = s:create_index('pk')
+---
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{2}
+---
+- [2]
+...
+s:replace{3}
+---
+- [3]
+...
+s:replace{4}
+---
+- [4]
+...
+c = net:connect(box.cfg.listen)
+---
+...
+--
+-- Ensure a request can be finalized from non-caller fibers.
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+---
+...
+ret = {}
+---
+...
+count = 0
+---
+...
+for i = 1, 10 do fiber.create(function() ret[i] = future:wait_result(1000) count = count + 1 end) end
+---
+...
+future:wait_result(0.01) -- Must fail on timeout.
+---
+- null
+- Timeout exceeded
+...
+finalize_long()
+---
+...
+while count ~= 10 do fiber.sleep(0.1) end
+---
+...
+ret
+---
+- - &0 [1, 2, 3]
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+...
+--
+-- Test discard.
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+---
+...
+future:discard()
+---
+...
+finalize_long()
+---
+...
+future:result()
+---
+- null
+- Response is discarded
+...
+future:wait_result(100)
+---
+- null
+- Response is discarded
+...
+box.schema.func.drop('long_function')
+---
+...
+c:close()
+---
+...
+s:drop()
+---
+...
diff --git a/test/box/net.box_discard_gh-3107.test.lua b/test/box/net.box_discard_gh-3107.test.lua
new file mode 100644
index 000000000..71f08a411
--- /dev/null
+++ b/test/box/net.box_discard_gh-3107.test.lua
@@ -0,0 +1,44 @@
+fiber = require 'fiber'
+net = require('net.box')
+
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+box.schema.func.create('long_function')
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+s = box.schema.create_space('test')
+pk = s:create_index('pk')
+s:replace{1}
+s:replace{2}
+s:replace{3}
+s:replace{4}
+c = net:connect(box.cfg.listen)
+
+--
+-- Ensure a request can be finalized from non-caller fibers.
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+ret = {}
+count = 0
+for i = 1, 10 do fiber.create(function() ret[i] = future:wait_result(1000) count = count + 1 end) end
+future:wait_result(0.01) -- Must fail on timeout.
+finalize_long()
+while count ~= 10 do fiber.sleep(0.1) end
+ret
+
+--
+-- Test discard.
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+future:discard()
+finalize_long()
+future:result()
+future:wait_result(100)
+
+box.schema.func.drop('long_function')
+
+c:close()
+s:drop()
diff --git a/test/box/net.box_disconnect_gh-3859.result b/test/box/net.box_disconnect_gh-3859.result
new file mode 100644
index 000000000..eae259740
--- /dev/null
+++ b/test/box/net.box_disconnect_gh-3859.result
@@ -0,0 +1,113 @@
+fiber = require 'fiber'
+---
+...
+test_run = require('test_run').new()
+---
+...
+net = require('net.box')
+---
+...
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+---
+- true
+...
+box.schema.func.create('fast_call')
+---
+...
+box.schema.func.create('long_call')
+---
+...
+box.schema.func.create('wait_signal')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'fast_call')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'long_call')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'wait_signal')
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+disconnected = false
+---
+...
+function on_disconnect() disconnected = true end
+---
+...
+-- Make sure all dangling connections are collected so
+-- that on_disconnect trigger isn't called spuriously.
+collectgarbage('collect')
+---
+- 0
+...
+fiber.sleep(0)
+---
+...
+box.session.on_disconnect(on_disconnect) == on_disconnect
+---
+- true
+...
+--
+-- gh-3859: on_disconnect is called only after all requests are
+-- processed, but should be called right after disconnect and
+-- only once.
+--
+ch1 = fiber.channel(1)
+---
+...
+ch2 = fiber.channel(1)
+---
+...
+function wait_signal() ch1:put(true) ch2:get() end
+---
+...
+_ = fiber.create(function() c:call('wait_signal') end)
+---
+...
+ch1:get()
+---
+- true
+...
+c:close()
+---
+...
+fiber.sleep(0)
+---
+...
+while disconnected == false do fiber.sleep(0.01) end
+---
+...
+disconnected -- true
+---
+- true
+...
+disconnected = nil
+---
+...
+ch2:put(true)
+---
+- true
+...
+fiber.sleep(0)
+---
+...
+disconnected -- nil, on_disconnect is not called second time.
+---
+- null
+...
+box.session.on_disconnect(nil, on_disconnect)
+---
+...
+box.schema.func.drop('long_call')
+---
+...
+box.schema.func.drop('fast_call')
+---
+...
+box.schema.func.drop('wait_signal')
+---
+...
diff --git a/test/box/net.box_disconnect_gh-3859.test.lua b/test/box/net.box_disconnect_gh-3859.test.lua
new file mode 100644
index 000000000..e0ec1a8ea
--- /dev/null
+++ b/test/box/net.box_disconnect_gh-3859.test.lua
@@ -0,0 +1,50 @@
+fiber = require 'fiber'
+test_run = require('test_run').new()
+net = require('net.box')
+
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+
+box.schema.func.create('fast_call')
+box.schema.func.create('long_call')
+box.schema.func.create('wait_signal')
+box.schema.user.grant('guest', 'execute', 'function', 'fast_call')
+box.schema.user.grant('guest', 'execute', 'function', 'long_call')
+box.schema.user.grant('guest', 'execute', 'function', 'wait_signal')
+c = net.connect(box.cfg.listen)
+
+disconnected = false
+function on_disconnect() disconnected = true end
+
+-- Make sure all dangling connections are collected so
+-- that on_disconnect trigger isn't called spuriously.
+collectgarbage('collect')
+fiber.sleep(0)
+
+box.session.on_disconnect(on_disconnect) == on_disconnect
+
+--
+-- gh-3859: on_disconnect is called only after all requests are
+-- processed, but should be called right after disconnect and
+-- only once.
+--
+ch1 = fiber.channel(1)
+ch2 = fiber.channel(1)
+function wait_signal() ch1:put(true) ch2:get() end
+_ = fiber.create(function() c:call('wait_signal') end)
+ch1:get()
+
+c:close()
+fiber.sleep(0)
+while disconnected == false do fiber.sleep(0.01) end
+disconnected -- true
+disconnected = nil
+
+ch2:put(true)
+fiber.sleep(0)
+disconnected -- nil, on_disconnect is not called second time.
+
+box.session.on_disconnect(nil, on_disconnect)
+
+box.schema.func.drop('long_call')
+box.schema.func.drop('fast_call')
+box.schema.func.drop('wait_signal')
diff --git a/test/box/net.box_fiber-async_gh-3107.result b/test/box/net.box_fiber-async_gh-3107.result
new file mode 100644
index 000000000..aaaca351a
--- /dev/null
+++ b/test/box/net.box_fiber-async_gh-3107.result
@@ -0,0 +1,115 @@
+fiber = require 'fiber'
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+---
+...
+box.schema.func.create('long_function')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+---
+...
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+---
+...
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+---
+...
+s = box.schema.create_space('test')
+---
+...
+pk = s:create_index('pk')
+---
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{2}
+---
+- [2]
+...
+s:replace{3}
+---
+- [3]
+...
+s:replace{4}
+---
+- [4]
+...
+c = net:connect(box.cfg.listen)
+---
+...
+--
+-- Check long connections, multiple wait_result().
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+---
+...
+future:result()
+---
+- null
+- Response is not ready
+...
+future:is_ready()
+---
+- false
+...
+future:wait_result(0.01) -- Must fail on timeout.
+---
+- null
+- Timeout exceeded
+...
+finalize_long()
+---
+...
+ret = future:wait_result(100)
+---
+...
+future:is_ready()
+---
+- true
+...
+-- Any timeout is ok - response is received already.
+future:wait_result(0)
+---
+- [1, 2, 3]
+...
+future:wait_result(0.01)
+---
+- [1, 2, 3]
+...
+ret
+---
+- [1, 2, 3]
+...
+_, err = pcall(future.wait_result, future, true)
+---
+...
+err:find('Usage') ~= nil
+---
+- true
+...
+_, err = pcall(future.wait_result, future, '100')
+---
+...
+err:find('Usage') ~= nil
+---
+- true
+...
+box.schema.func.drop('long_function')
+---
+...
+c:close()
+---
+...
+s:drop()
+---
+...
diff --git a/test/box/net.box_fiber-async_gh-3107.test.lua b/test/box/net.box_fiber-async_gh-3107.test.lua
new file mode 100644
index 000000000..d23f368cb
--- /dev/null
+++ b/test/box/net.box_fiber-async_gh-3107.test.lua
@@ -0,0 +1,42 @@
+fiber = require 'fiber'
+net = require('net.box')
+
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+box.schema.func.create('long_function')
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+s = box.schema.create_space('test')
+pk = s:create_index('pk')
+s:replace{1}
+s:replace{2}
+s:replace{3}
+s:replace{4}
+c = net:connect(box.cfg.listen)
+--
+-- Check long connections, multiple wait_result().
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+future:result()
+future:is_ready()
+future:wait_result(0.01) -- Must fail on timeout.
+finalize_long()
+ret = future:wait_result(100)
+future:is_ready()
+-- Any timeout is ok - response is received already.
+future:wait_result(0)
+future:wait_result(0.01)
+ret
+
+_, err = pcall(future.wait_result, future, true)
+err:find('Usage') ~= nil
+_, err = pcall(future.wait_result, future, '100')
+err:find('Usage') ~= nil
+
+box.schema.func.drop('long_function')
+
+c:close()
+s:drop()
diff --git a/test/box/net.box_field_names_gh-2978.result b/test/box/net.box_field_names_gh-2978.result
new file mode 100644
index 000000000..2b6ea9c44
--- /dev/null
+++ b/test/box/net.box_field_names_gh-2978.result
@@ -0,0 +1,101 @@
+net = require('net.box')
+---
+...
+--
+-- gh-2978: field names for tuples received from netbox.
+--
+_ = box.schema.create_space("named", {format = {{name = "id"}, {name="abc"}}})
+---
+...
+_ = box.space.named:create_index('id', {parts = {{1, 'unsigned'}}})
+---
+...
+box.space.named:insert({1, 1})
+---
+- [1, 1]
+...
+box.schema.user.grant('guest', 'read, write, execute', 'space')
+---
+...
+cn = net.connect(box.cfg.listen)
+---
+...
+s = cn.space.named
+---
+...
+s:get{1}.id
+---
+- 1
+...
+s:get{1}:tomap()
+---
+- 1: 1
+  2: 1
+  abc: 1
+  id: 1
+...
+s:insert{2,3}:tomap()
+---
+- 1: 2
+  2: 3
+  abc: 3
+  id: 2
+...
+s:replace{2,14}:tomap()
+---
+- 1: 2
+  2: 14
+  abc: 14
+  id: 2
+...
+s:update(1, {{'+', 2, 10}}):tomap()
+---
+- 1: 1
+  2: 11
+  abc: 11
+  id: 1
+...
+s:select()[1]:tomap()
+---
+- 1: 1
+  2: 11
+  abc: 11
+  id: 1
+...
+s:delete({2}):tomap()
+---
+- 1: 2
+  2: 14
+  abc: 14
+  id: 2
+...
+-- Check that formats changes after reload.
+box.space.named:format({{name = "id2"}, {name="abc2"}})
+---
+...
+s:select()[1]:tomap()
+---
+- 1: 1
+  2: 11
+  abc: 11
+  id: 1
+...
+cn:reload_schema()
+---
+...
+s:select()[1]:tomap()
+---
+- 1: 1
+  2: 11
+  id2: 1
+  abc2: 11
+...
+cn:close()
+---
+...
+box.space.named:drop()
+---
+...
+box.schema.user.revoke('guest', 'read, write, execute', 'space')
+---
+...
diff --git a/test/box/net.box_field_names_gh-2978.test.lua b/test/box/net.box_field_names_gh-2978.test.lua
new file mode 100644
index 000000000..a5dccf16a
--- /dev/null
+++ b/test/box/net.box_field_names_gh-2978.test.lua
@@ -0,0 +1,29 @@
+net = require('net.box')
+
+--
+-- gh-2978: field names for tuples received from netbox.
+--
+_ = box.schema.create_space("named", {format = {{name = "id"}, {name="abc"}}})
+_ = box.space.named:create_index('id', {parts = {{1, 'unsigned'}}})
+box.space.named:insert({1, 1})
+box.schema.user.grant('guest', 'read, write, execute', 'space')
+cn = net.connect(box.cfg.listen)
+
+s = cn.space.named
+s:get{1}.id
+s:get{1}:tomap()
+s:insert{2,3}:tomap()
+s:replace{2,14}:tomap()
+s:update(1, {{'+', 2, 10}}):tomap()
+s:select()[1]:tomap()
+s:delete({2}):tomap()
+
+-- Check that formats changes after reload.
+box.space.named:format({{name = "id2"}, {name="abc2"}})
+s:select()[1]:tomap()
+cn:reload_schema()
+s:select()[1]:tomap()
+
+cn:close()
+box.space.named:drop()
+box.schema.user.revoke('guest', 'read, write, execute', 'space')
diff --git a/test/box/net.box_get_connection_object.result b/test/box/net.box_get_connection_object.result
new file mode 100644
index 000000000..f461477ed
--- /dev/null
+++ b/test/box/net.box_get_connection_object.result
@@ -0,0 +1,40 @@
+net = require('net.box')
+---
+...
+--
+-- Check that it's possible to get connection object form net.box space
+--
+space = box.schema.space.create('test', {format={{name="id", type="unsigned"}}})
+---
+...
+space ~= nil
+---
+- true
+...
+_ = box.space.test:create_index('primary')
+---
+...
+box.schema.user.grant('guest','read,write,execute','space', 'test')
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+c:ping()
+---
+- true
+...
+c.space.test ~= nil
+---
+- true
+...
+c.space.test.connection == c
+---
+- true
+...
+box.schema.user.revoke('guest','read,write,execute','space', 'test')
+---
+...
+c:close()
+---
+...
diff --git a/test/box/net.box_get_connection_object.test.lua b/test/box/net.box_get_connection_object.test.lua
new file mode 100644
index 000000000..71ed110b9
--- /dev/null
+++ b/test/box/net.box_get_connection_object.test.lua
@@ -0,0 +1,19 @@
+net = require('net.box')
+
+--
+-- Check that it's possible to get connection object form net.box space
+--
+
+space = box.schema.space.create('test', {format={{name="id", type="unsigned"}}})
+space ~= nil
+_ = box.space.test:create_index('primary')
+box.schema.user.grant('guest','read,write,execute','space', 'test')
+
+c = net.connect(box.cfg.listen)
+
+c:ping()
+c.space.test ~= nil
+
+c.space.test.connection == c
+box.schema.user.revoke('guest','read,write,execute','space', 'test')
+c:close()
diff --git a/test/box/net.box_gibberish_gh-3900.result b/test/box/net.box_gibberish_gh-3900.result
new file mode 100644
index 000000000..302c74c9f
--- /dev/null
+++ b/test/box/net.box_gibberish_gh-3900.result
@@ -0,0 +1,31 @@
+test_run = require('test_run').new()
+---
+...
+LISTEN = require('uri').parse(box.cfg.listen)
+---
+...
+--
+-- gh-3900: tarantool can be crashed by sending gibberish to a
+-- binary socket
+--
+socket = require("socket")
+---
+...
+sock = socket.tcp_connect(LISTEN.host, LISTEN.service)
+---
+...
+data = string.fromhex("6783000000000000000000000000000000000000000000800000C8000000000000000000000000000000000000000000FFFF210100373208000000FFFF000055AAEB66486472530D02000000000010A0350001008000001000000000000000000000000000D05700")
+---
+...
+sock:write(data)
+---
+- 104
+...
+test_run:wait_log('default', 'ER_INVALID_MSGPACK: Invalid MsgPack %- packet body', nil, 10)
+---
+- 'ER_INVALID_MSGPACK: Invalid MsgPack - packet body'
+...
+sock:close()
+---
+- true
+...
diff --git a/test/box/net.box_gibberish_gh-3900.test.lua b/test/box/net.box_gibberish_gh-3900.test.lua
new file mode 100644
index 000000000..7debfd4b3
--- /dev/null
+++ b/test/box/net.box_gibberish_gh-3900.test.lua
@@ -0,0 +1,13 @@
+test_run = require('test_run').new()
+LISTEN = require('uri').parse(box.cfg.listen)
+
+--
+-- gh-3900: tarantool can be crashed by sending gibberish to a
+-- binary socket
+--
+socket = require("socket")
+sock = socket.tcp_connect(LISTEN.host, LISTEN.service)
+data = string.fromhex("6783000000000000000000000000000000000000000000800000C8000000000000000000000000000000000000000000FFFF210100373208000000FFFF000055AAEB66486472530D02000000000010A0350001008000001000000000000000000000000000D05700")
+sock:write(data)
+test_run:wait_log('default', 'ER_INVALID_MSGPACK: Invalid MsgPack %- packet body', nil, 10)
+sock:close()
diff --git a/test/box/net.box_huge_data_gh-983.result b/test/box/net.box_huge_data_gh-983.result
new file mode 100644
index 000000000..e9b470e28
--- /dev/null
+++ b/test/box/net.box_huge_data_gh-983.result
@@ -0,0 +1,30 @@
+-- gh-983 selecting a lot of data crashes the server or hangs the
+-- connection
+-- gh-983 test case: iproto connection selecting a lot of data
+_ = box.schema.space.create('test', { temporary = true })
+---
+...
+_ = box.space.test:create_index('primary', {type = 'TREE', parts = {1,'unsigned'}})
+---
+...
+data1k = "aaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhh"
+---
+...
+for i = 0,10000 do box.space.test:insert{i, data1k} end
+---
+...
+box.schema.user.grant('guest', 'read', 'space', 'test')
+---
+...
+net = require('net.box')
+---
+...
+c = net:connect(box.cfg.listen)
+---
+...
+r = c.space.test:select(nil, {limit=5000})
+---
+...
+box.space.test:drop()
+---
+...
diff --git a/test/box/net.box_huge_data_gh-983.test.lua b/test/box/net.box_huge_data_gh-983.test.lua
new file mode 100644
index 000000000..93df08834
--- /dev/null
+++ b/test/box/net.box_huge_data_gh-983.test.lua
@@ -0,0 +1,16 @@
+-- gh-983 selecting a lot of data crashes the server or hangs the
+-- connection
+
+-- gh-983 test case: iproto connection selecting a lot of data
+_ = box.schema.space.create('test', { temporary = true })
+_ = box.space.test:create_index('primary', {type = 'TREE', parts = {1,'unsigned'}})
+
+data1k = "aaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhhaaaabbbbccccddddeeeeffffgggghhhh"
+
+for i = 0,10000 do box.space.test:insert{i, data1k} end
+
+box.schema.user.grant('guest', 'read', 'space', 'test')
+net = require('net.box')
+c = net:connect(box.cfg.listen)
+r = c.space.test:select(nil, {limit=5000})
+box.space.test:drop()
diff --git a/test/box/net.box_incompatible_index-gh-1729.result b/test/box/net.box_incompatible_index-gh-1729.result
new file mode 100644
index 000000000..1d9fa542e
--- /dev/null
+++ b/test/box/net.box_incompatible_index-gh-1729.result
@@ -0,0 +1,99 @@
+test_run = require('test_run').new()
+---
+...
+net = require('net.box')
+---
+...
+test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '")
+---
+- true
+...
+_ = box.schema.space.create('test')
+---
+...
+_ = box.space.test:create_index('primary', {type = 'TREE', parts = {1,'unsigned'}})
+---
+...
+_ = box.space.test:create_index('covering', {type = 'TREE', parts = {1,'unsigned',3,'string',2,'unsigned'}})
+---
+...
+_ = box.space.test:insert{1, 2, "string"}
+---
+...
+box.schema.user.grant('guest', 'read,write', 'space', 'test')
+---
+...
+c = net:connect(box.cfg.listen)
+---
+...
+-- gh-1729 net.box index metadata incompatible with local metadata
+c.space.test.index.primary.parts
+---
+- - type: unsigned
+    is_nullable: false
+    fieldno: 1
+...
+c.space.test.index.covering.parts
+---
+- - type: unsigned
+    is_nullable: false
+    fieldno: 1
+  - type: string
+    is_nullable: false
+    fieldno: 3
+  - type: unsigned
+    is_nullable: false
+    fieldno: 2
+...
+box.space.test:drop()
+---
+...
+-- CALL vs CALL_16 in connect options
+function echo(...) return ... end
+---
+...
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+c:call('echo', {42})
+---
+- 42
+...
+c:eval('return echo(...)', {42})
+---
+- 42
+...
+-- invalid arguments
+c:call('echo', 42)
+---
+- error: 'builtin/box/net_box.lua..."]:<line>: Use remote:call(func_name, {arg1, arg2, ...},
+    opts) instead of remote:call(func_name, arg1, arg2, ...)'
+...
+c:eval('return echo(...)', 42)
+---
+- error: 'builtin/box/net_box.lua..."]:<line>: Use remote:eval(expression, {arg1, arg2, ...},
+    opts) instead of remote:eval(expression, arg1, arg2, ...)'
+...
+c:close()
+---
+...
+c = net.connect(box.cfg.listen, {call_16 = true})
+---
+...
+c:call('echo', 42)
+---
+- - [42]
+...
+c:eval('return echo(...)', 42)
+---
+- 42
+...
+c:close()
+---
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
diff --git a/test/box/net.box_incompatible_index-gh-1729.test.lua b/test/box/net.box_incompatible_index-gh-1729.test.lua
new file mode 100644
index 000000000..2d25b9017
--- /dev/null
+++ b/test/box/net.box_incompatible_index-gh-1729.test.lua
@@ -0,0 +1,33 @@
+test_run = require('test_run').new()
+net = require('net.box')
+
+test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '")
+
+_ = box.schema.space.create('test')
+_ = box.space.test:create_index('primary', {type = 'TREE', parts = {1,'unsigned'}})
+_ = box.space.test:create_index('covering', {type = 'TREE', parts = {1,'unsigned',3,'string',2,'unsigned'}})
+_ = box.space.test:insert{1, 2, "string"}
+box.schema.user.grant('guest', 'read,write', 'space', 'test')
+c = net:connect(box.cfg.listen)
+
+-- gh-1729 net.box index metadata incompatible with local metadata
+c.space.test.index.primary.parts
+c.space.test.index.covering.parts
+
+box.space.test:drop()
+
+-- CALL vs CALL_16 in connect options
+function echo(...) return ... end
+box.schema.user.grant('guest', 'execute', 'universe')
+c = net.connect(box.cfg.listen)
+c:call('echo', {42})
+c:eval('return echo(...)', {42})
+-- invalid arguments
+c:call('echo', 42)
+c:eval('return echo(...)', 42)
+c:close()
+c = net.connect(box.cfg.listen, {call_16 = true})
+c:call('echo', 42)
+c:eval('return echo(...)', 42)
+c:close()
+box.schema.user.revoke('guest', 'execute', 'universe')
diff --git a/test/box/net.box_incorrect_iterator_gh-841.result b/test/box/net.box_incorrect_iterator_gh-841.result
new file mode 100644
index 000000000..4bdd1afa3
--- /dev/null
+++ b/test/box/net.box_incorrect_iterator_gh-841.result
@@ -0,0 +1,497 @@
+remote = require 'net.box'
+---
+...
+fiber = require 'fiber'
+---
+...
+test_run = require('test_run').new()
+---
+...
+test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '")
+---
+- true
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+function x_select(cn, space_id, index_id, iterator, offset, limit, key, opts)
+    local ret = cn:_request('select', opts, nil, space_id, index_id, iterator,
+                            offset, limit, key)
+    return ret
+end
+function x_fatal(cn) cn._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80') end
+test_run:cmd("setopt delimiter ''");
+---
+...
+LISTEN = require('uri').parse(box.cfg.listen)
+---
+...
+space = box.schema.space.create('net_box_test_space')
+---
+...
+index = space:create_index('primary', { type = 'tree' })
+---
+...
+function test_foo(a,b,c) return { {{ [a] = 1 }}, {{ [b] = 2 }}, c } end
+---
+...
+box.schema.user.grant('guest', 'read,write', 'space', 'net_box_test_space')
+---
+...
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+cn = remote.connect(box.cfg.listen)
+---
+...
+x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 0xFFFFFFFF, 123)
+---
+- []
+...
+space:insert{123, 345}
+---
+- [123, 345]
+...
+x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 0, 123)
+---
+- []
+...
+x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 1, 123)
+---
+- - [123, 345]
+...
+x_select(cn, space.id, space.index.primary.id, box.index.EQ, 1, 1, 123)
+---
+- []
+...
+cn.space[space.id]  ~= nil
+---
+- true
+...
+cn.space.net_box_test_space ~= nil
+---
+- true
+...
+cn.space.net_box_test_space ~= nil
+---
+- true
+...
+cn.space.net_box_test_space.index ~= nil
+---
+- true
+...
+cn.space.net_box_test_space.index.primary ~= nil
+---
+- true
+...
+cn.space.net_box_test_space.index[space.index.primary.id] ~= nil
+---
+- true
+...
+cn.space.net_box_test_space.index.primary:select(123)
+---
+- - [123, 345]
+...
+cn.space.net_box_test_space.index.primary:select(123, { limit = 0 })
+---
+- []
+...
+cn.space.net_box_test_space.index.primary:select(nil, { limit = 1, })
+---
+- - [123, 345]
+...
+cn.space.net_box_test_space:insert{234, 1,2,3}
+---
+- [234, 1, 2, 3]
+...
+cn.space.net_box_test_space:insert{234, 1,2,3}
+---
+- error: Duplicate key exists in unique index 'primary' in space 'net_box_test_space'
+...
+cn.space.net_box_test_space.insert{234, 1,2,3}
+---
+- error: 'builtin/box/schema.lua..."]:<line>: Use space:insert(...) instead of space.insert(...)'
+...
+cn.space.net_box_test_space:replace{354, 1,2,3}
+---
+- [354, 1, 2, 3]
+...
+cn.space.net_box_test_space:replace{354, 1,2,4}
+---
+- [354, 1, 2, 4]
+...
+cn.space.net_box_test_space:select{123}
+---
+- - [123, 345]
+...
+space:select({123}, { iterator = 'GE' })
+---
+- - [123, 345]
+  - [234, 1, 2, 3]
+  - [354, 1, 2, 4]
+...
+cn.space.net_box_test_space:select({123}, { iterator = 'GE' })
+---
+- - [123, 345]
+  - [234, 1, 2, 3]
+  - [354, 1, 2, 4]
+...
+cn.space.net_box_test_space:select({123}, { iterator = 'GT' })
+---
+- - [234, 1, 2, 3]
+  - [354, 1, 2, 4]
+...
+cn.space.net_box_test_space:select({123}, { iterator = 'GT', limit = 1 })
+---
+- - [234, 1, 2, 3]
+...
+cn.space.net_box_test_space:select({123}, { iterator = 'GT', limit = 1, offset = 1 })
+---
+- - [354, 1, 2, 4]
+...
+cn.space.net_box_test_space:select{123}
+---
+- - [123, 345]
+...
+cn.space.net_box_test_space:update({123}, { { '+', 2, 1 } })
+---
+- [123, 346]
+...
+cn.space.net_box_test_space:update(123, { { '+', 2, 1 } })
+---
+- [123, 347]
+...
+cn.space.net_box_test_space:select{123}
+---
+- - [123, 347]
+...
+cn.space.net_box_test_space:insert(cn.space.net_box_test_space:get{123}:update{ { '=', 1, 2 } })
+---
+- [2, 347]
+...
+cn.space.net_box_test_space:delete{123}
+---
+- [123, 347]
+...
+cn.space.net_box_test_space:select{2}
+---
+- - [2, 347]
+...
+cn.space.net_box_test_space:select({234}, { iterator = 'LT' })
+---
+- - [2, 347]
+...
+cn.space.net_box_test_space:update({1}, { { '+', 2, 2 } })
+---
+...
+cn.space.net_box_test_space:delete{1}
+---
+...
+cn.space.net_box_test_space:delete{2}
+---
+- [2, 347]
+...
+cn.space.net_box_test_space:delete{2}
+---
+...
+-- test one-based indexing in splice operation (see update.test.lua)
+cn.space.net_box_test_space:replace({10, 'abcde'})
+---
+- [10, 'abcde']
+...
+cn.space.net_box_test_space:update(10,  {{':', 2, 0, 0, '!'}})
+---
+- error: 'SPLICE error on field 2: offset is out of bound'
+...
+cn.space.net_box_test_space:update(10,  {{':', 2, 1, 0, '('}})
+---
+- [10, '(abcde']
+...
+cn.space.net_box_test_space:update(10,  {{':', 2, 2, 0, '({'}})
+---
+- [10, '(({abcde']
+...
+cn.space.net_box_test_space:update(10,  {{':', 2, -1, 0, ')'}})
+---
+- [10, '(({abcde)']
+...
+cn.space.net_box_test_space:update(10,  {{':', 2, -2, 0, '})'}})
+---
+- [10, '(({abcde}))']
+...
+cn.space.net_box_test_space:delete{10}
+---
+- [10, '(({abcde}))']
+...
+cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
+---
+- - [234, 1, 2, 3]
+  - [354, 1, 2, 4]
+...
+-- gh-841: net.box uses incorrect iterator type for select with no arguments
+cn.space.net_box_test_space:select()
+---
+- - [234, 1, 2, 3]
+  - [354, 1, 2, 4]
+...
+cn.space.net_box_test_space.index.primary:min()
+---
+- [234, 1, 2, 3]
+...
+cn.space.net_box_test_space.index.primary:min(354)
+---
+- [354, 1, 2, 4]
+...
+cn.space.net_box_test_space.index.primary:max()
+---
+- [354, 1, 2, 4]
+...
+cn.space.net_box_test_space.index.primary:max(234)
+---
+- [234, 1, 2, 3]
+...
+cn.space.net_box_test_space.index.primary:count()
+---
+- 2
+...
+cn.space.net_box_test_space.index.primary:count(354)
+---
+- 1
+...
+cn.space.net_box_test_space:get(354)
+---
+- [354, 1, 2, 4]
+...
+-- reconnects after errors
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
+box.schema.func.create('test_foo')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'test_foo')
+---
+...
+-- -- 1. no reconnect
+x_fatal(cn)
+---
+...
+cn.state
+---
+- error
+...
+cn:ping()
+---
+- false
+...
+cn:call('test_foo')
+---
+- error: Peer closed
+...
+cn:wait_state('active')
+---
+- false
+...
+-- -- 2 reconnect
+cn = remote.connect(LISTEN.host, LISTEN.service, { reconnect_after = .1 })
+---
+...
+cn.space ~= nil
+---
+- true
+...
+cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
+---
+- - [234, 1, 2, 3]
+  - [354, 1, 2, 4]
+...
+x_fatal(cn)
+---
+...
+cn:wait_connected()
+---
+- true
+...
+cn:wait_state('active')
+---
+- true
+...
+cn:wait_state({active=true})
+---
+- true
+...
+cn:ping()
+---
+- true
+...
+cn.state
+---
+- active
+...
+cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
+---
+- - [234, 1, 2, 3]
+  - [354, 1, 2, 4]
+...
+x_fatal(cn)
+---
+...
+x_select(cn, space.id, 0, box.index.ALL, 0, 0xFFFFFFFF, {})
+---
+- - [234, 1, 2, 3]
+  - [354, 1, 2, 4]
+...
+cn.state
+---
+- active
+...
+cn:ping()
+---
+- true
+...
+-- -- dot-new-method
+cn1 = remote.new(LISTEN.host, LISTEN.service)
+---
+...
+x_select(cn1, space.id, 0, box.index.ALL, 0, 0xFFFFFFF, {})
+---
+- - [234, 1, 2, 3]
+  - [354, 1, 2, 4]
+...
+cn1:close()
+---
+...
+-- -- error while waiting for response
+type(fiber.create(function() fiber.sleep(.5) x_fatal(cn) end))
+---
+- userdata
+...
+function pause() fiber.sleep(10) return true end
+---
+...
+box.schema.func.create('pause')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'pause')
+---
+...
+cn:call('pause')
+---
+- error: Peer closed
+...
+cn:call('test_foo', {'a', 'b', 'c'})
+---
+- [[{'a': 1}], [{'b': 2}], 'c']
+...
+box.schema.func.drop('pause')
+---
+...
+-- call
+remote.self:call('test_foo', {'a', 'b', 'c'})
+---
+- - - a: 1
+  - - b: 2
+  - c
+...
+cn:call('test_foo', {'a', 'b', 'c'})
+---
+- [[{'a': 1}], [{'b': 2}], 'c']
+...
+box.schema.func.drop('test_foo')
+---
+...
+box.schema.func.create('long_rep')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'long_rep')
+---
+...
+-- long replies
+function long_rep() return { 1,  string.rep('a', 5000) } end
+---
+...
+res = cn:call('long_rep')
+---
+...
+res[1] == 1
+---
+- true
+...
+res[2] == string.rep('a', 5000)
+---
+- true
+...
+function long_rep() return { 1,  string.rep('a', 50000) } end
+---
+...
+res = cn:call('long_rep')
+---
+...
+res[1] == 1
+---
+- true
+...
+res[2] == string.rep('a', 50000)
+---
+- true
+...
+box.schema.func.drop('long_rep')
+---
+...
+-- a.b.c.d
+u = '84F7BCFA-079C-46CC-98B4-F0C821BE833E'
+---
+...
+X = {}
+---
+...
+X.X = X
+---
+...
+function X.fn(x,y) return y or x end
+---
+...
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+cn:close()
+---
+...
+cn = remote.connect(LISTEN.host, LISTEN.service)
+---
+...
+cn:call('X.fn', {u})
+---
+- 84F7BCFA-079C-46CC-98B4-F0C821BE833E
+...
+cn:call('X.X.X.X.X.X.X.fn', {u})
+---
+- 84F7BCFA-079C-46CC-98B4-F0C821BE833E
+...
+cn:call('X.X.X.X:fn', {u})
+---
+- 84F7BCFA-079C-46CC-98B4-F0C821BE833E
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
+cn:close()
+---
+...
+-- auth
+cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123', wait_connected = true })
+---
+...
+cn:is_connected()
+---
+- false
+...
+cn.error
+---
+- User 'netbox' is not found
+...
+cn.state
+---
+- error
+...
diff --git a/test/box/net.box_incorrect_iterator_gh-841.test.lua b/test/box/net.box_incorrect_iterator_gh-841.test.lua
new file mode 100644
index 000000000..cd431a57a
--- /dev/null
+++ b/test/box/net.box_incorrect_iterator_gh-841.test.lua
@@ -0,0 +1,182 @@
+remote = require 'net.box'
+fiber = require 'fiber'
+test_run = require('test_run').new()
+test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '")
+
+test_run:cmd("setopt delimiter ';'")
+function x_select(cn, space_id, index_id, iterator, offset, limit, key, opts)
+    local ret = cn:_request('select', opts, nil, space_id, index_id, iterator,
+                            offset, limit, key)
+    return ret
+end
+function x_fatal(cn) cn._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80') end
+test_run:cmd("setopt delimiter ''");
+
+LISTEN = require('uri').parse(box.cfg.listen)
+space = box.schema.space.create('net_box_test_space')
+index = space:create_index('primary', { type = 'tree' })
+
+function test_foo(a,b,c) return { {{ [a] = 1 }}, {{ [b] = 2 }}, c } end
+
+box.schema.user.grant('guest', 'read,write', 'space', 'net_box_test_space')
+box.schema.user.grant('guest', 'execute', 'universe')
+
+cn = remote.connect(box.cfg.listen)
+
+x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 0xFFFFFFFF, 123)
+space:insert{123, 345}
+x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 0, 123)
+x_select(cn, space.id, space.index.primary.id, box.index.EQ, 0, 1, 123)
+x_select(cn, space.id, space.index.primary.id, box.index.EQ, 1, 1, 123)
+
+cn.space[space.id]  ~= nil
+cn.space.net_box_test_space ~= nil
+cn.space.net_box_test_space ~= nil
+cn.space.net_box_test_space.index ~= nil
+cn.space.net_box_test_space.index.primary ~= nil
+cn.space.net_box_test_space.index[space.index.primary.id] ~= nil
+
+
+cn.space.net_box_test_space.index.primary:select(123)
+cn.space.net_box_test_space.index.primary:select(123, { limit = 0 })
+cn.space.net_box_test_space.index.primary:select(nil, { limit = 1, })
+cn.space.net_box_test_space:insert{234, 1,2,3}
+cn.space.net_box_test_space:insert{234, 1,2,3}
+cn.space.net_box_test_space.insert{234, 1,2,3}
+
+cn.space.net_box_test_space:replace{354, 1,2,3}
+cn.space.net_box_test_space:replace{354, 1,2,4}
+
+cn.space.net_box_test_space:select{123}
+space:select({123}, { iterator = 'GE' })
+cn.space.net_box_test_space:select({123}, { iterator = 'GE' })
+cn.space.net_box_test_space:select({123}, { iterator = 'GT' })
+cn.space.net_box_test_space:select({123}, { iterator = 'GT', limit = 1 })
+cn.space.net_box_test_space:select({123}, { iterator = 'GT', limit = 1, offset = 1 })
+
+cn.space.net_box_test_space:select{123}
+cn.space.net_box_test_space:update({123}, { { '+', 2, 1 } })
+cn.space.net_box_test_space:update(123, { { '+', 2, 1 } })
+cn.space.net_box_test_space:select{123}
+
+cn.space.net_box_test_space:insert(cn.space.net_box_test_space:get{123}:update{ { '=', 1, 2 } })
+cn.space.net_box_test_space:delete{123}
+cn.space.net_box_test_space:select{2}
+cn.space.net_box_test_space:select({234}, { iterator = 'LT' })
+
+cn.space.net_box_test_space:update({1}, { { '+', 2, 2 } })
+
+cn.space.net_box_test_space:delete{1}
+cn.space.net_box_test_space:delete{2}
+cn.space.net_box_test_space:delete{2}
+
+-- test one-based indexing in splice operation (see update.test.lua)
+cn.space.net_box_test_space:replace({10, 'abcde'})
+cn.space.net_box_test_space:update(10,  {{':', 2, 0, 0, '!'}})
+cn.space.net_box_test_space:update(10,  {{':', 2, 1, 0, '('}})
+cn.space.net_box_test_space:update(10,  {{':', 2, 2, 0, '({'}})
+cn.space.net_box_test_space:update(10,  {{':', 2, -1, 0, ')'}})
+cn.space.net_box_test_space:update(10,  {{':', 2, -2, 0, '})'}})
+cn.space.net_box_test_space:delete{10}
+
+cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
+-- gh-841: net.box uses incorrect iterator type for select with no arguments
+cn.space.net_box_test_space:select()
+
+cn.space.net_box_test_space.index.primary:min()
+cn.space.net_box_test_space.index.primary:min(354)
+cn.space.net_box_test_space.index.primary:max()
+cn.space.net_box_test_space.index.primary:max(234)
+cn.space.net_box_test_space.index.primary:count()
+cn.space.net_box_test_space.index.primary:count(354)
+
+cn.space.net_box_test_space:get(354)
+
+-- reconnects after errors
+
+box.schema.user.revoke('guest', 'execute', 'universe')
+box.schema.func.create('test_foo')
+box.schema.user.grant('guest', 'execute', 'function', 'test_foo')
+
+-- -- 1. no reconnect
+x_fatal(cn)
+cn.state
+cn:ping()
+cn:call('test_foo')
+cn:wait_state('active')
+
+-- -- 2 reconnect
+cn = remote.connect(LISTEN.host, LISTEN.service, { reconnect_after = .1 })
+cn.space ~= nil
+
+cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
+x_fatal(cn)
+cn:wait_connected()
+cn:wait_state('active')
+cn:wait_state({active=true})
+cn:ping()
+cn.state
+cn.space.net_box_test_space:select({}, { iterator = 'ALL' })
+
+x_fatal(cn)
+x_select(cn, space.id, 0, box.index.ALL, 0, 0xFFFFFFFF, {})
+
+cn.state
+cn:ping()
+
+-- -- dot-new-method
+
+cn1 = remote.new(LISTEN.host, LISTEN.service)
+x_select(cn1, space.id, 0, box.index.ALL, 0, 0xFFFFFFF, {})
+cn1:close()
+-- -- error while waiting for response
+type(fiber.create(function() fiber.sleep(.5) x_fatal(cn) end))
+function pause() fiber.sleep(10) return true end
+
+box.schema.func.create('pause')
+box.schema.user.grant('guest', 'execute', 'function', 'pause')
+cn:call('pause')
+cn:call('test_foo', {'a', 'b', 'c'})
+box.schema.func.drop('pause')
+
+-- call
+remote.self:call('test_foo', {'a', 'b', 'c'})
+cn:call('test_foo', {'a', 'b', 'c'})
+box.schema.func.drop('test_foo')
+
+box.schema.func.create('long_rep')
+box.schema.user.grant('guest', 'execute', 'function', 'long_rep')
+
+-- long replies
+function long_rep() return { 1,  string.rep('a', 5000) } end
+res = cn:call('long_rep')
+res[1] == 1
+res[2] == string.rep('a', 5000)
+
+function long_rep() return { 1,  string.rep('a', 50000) } end
+res = cn:call('long_rep')
+res[1] == 1
+res[2] == string.rep('a', 50000)
+
+box.schema.func.drop('long_rep')
+
+-- a.b.c.d
+u = '84F7BCFA-079C-46CC-98B4-F0C821BE833E'
+X = {}
+X.X = X
+function X.fn(x,y) return y or x end
+box.schema.user.grant('guest', 'execute', 'universe')
+cn:close()
+cn = remote.connect(LISTEN.host, LISTEN.service)
+cn:call('X.fn', {u})
+cn:call('X.X.X.X.X.X.X.fn', {u})
+cn:call('X.X.X.X:fn', {u})
+box.schema.user.revoke('guest', 'execute', 'universe')
+cn:close()
+
+-- auth
+
+cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123', wait_connected = true })
+cn:is_connected()
+cn.error
+cn.state
diff --git a/test/box/net.box_index_unique_flag_gh-4091.result b/test/box/net.box_index_unique_flag_gh-4091.result
new file mode 100644
index 000000000..a72c32c74
--- /dev/null
+++ b/test/box/net.box_index_unique_flag_gh-4091.result
@@ -0,0 +1,28 @@
+net = require('net.box')
+---
+...
+space = box.schema.space.create('test', {format={{name="id", type="unsigned"}}})
+---
+...
+_ = box.space.test:create_index('primary')
+---
+...
+box.schema.user.grant('guest', 'read', 'space', 'test')
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+--
+-- gh-4091: index unique flag is always false.
+--
+c.space.test.index.primary.unique
+---
+- true
+...
+c:close()
+---
+...
+space:drop()
+---
+...
diff --git a/test/box/net.box_index_unique_flag_gh-4091.test.lua b/test/box/net.box_index_unique_flag_gh-4091.test.lua
new file mode 100644
index 000000000..7027b1e33
--- /dev/null
+++ b/test/box/net.box_index_unique_flag_gh-4091.test.lua
@@ -0,0 +1,15 @@
+net = require('net.box')
+
+space = box.schema.space.create('test', {format={{name="id", type="unsigned"}}})
+_ = box.space.test:create_index('primary')
+box.schema.user.grant('guest', 'read', 'space', 'test')
+
+c = net.connect(box.cfg.listen)
+
+--
+-- gh-4091: index unique flag is always false.
+--
+c.space.test.index.primary.unique
+
+c:close()
+space:drop()
diff --git a/test/box/net.box_iproto_hangs_gh-3464.result b/test/box/net.box_iproto_hangs_gh-3464.result
new file mode 100644
index 000000000..d425bf78c
--- /dev/null
+++ b/test/box/net.box_iproto_hangs_gh-3464.result
@@ -0,0 +1,31 @@
+msgpack = require 'msgpack'
+---
+...
+test_run = require('test_run').new()
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-3464: iproto hangs in 100% CPU when too big packet size
+-- is received due to size_t overflow.
+--
+c = net:connect(box.cfg.listen)
+---
+...
+data = msgpack.encode(18400000000000000000)..'aaaaaaa'
+---
+...
+c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, data)
+---
+- null
+- Peer closed
+...
+c:close()
+---
+...
+test_run:grep_log('default', 'too big packet size in the header') ~= nil
+---
+- true
+...
diff --git a/test/box/net.box_iproto_hangs_gh-3464.test.lua b/test/box/net.box_iproto_hangs_gh-3464.test.lua
new file mode 100644
index 000000000..77551e415
--- /dev/null
+++ b/test/box/net.box_iproto_hangs_gh-3464.test.lua
@@ -0,0 +1,13 @@
+msgpack = require 'msgpack'
+test_run = require('test_run').new()
+net = require('net.box')
+
+--
+-- gh-3464: iproto hangs in 100% CPU when too big packet size
+-- is received due to size_t overflow.
+--
+c = net:connect(box.cfg.listen)
+data = msgpack.encode(18400000000000000000)..'aaaaaaa'
+c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, data)
+c:close()
+test_run:grep_log('default', 'too big packet size in the header') ~= nil
diff --git a/test/box/net.box_is_nullable_gh-3256.result b/test/box/net.box_is_nullable_gh-3256.result
new file mode 100644
index 000000000..5d6dc4b94
--- /dev/null
+++ b/test/box/net.box_is_nullable_gh-3256.result
@@ -0,0 +1,97 @@
+net = require('net.box')
+---
+...
+--
+-- gh-3256 net.box is_nullable and collation options output
+--
+space = box.schema.create_space('test')
+---
+...
+box.schema.user.grant('guest', 'read', 'space', 'test')
+---
+...
+_ = space:create_index('pk')
+---
+...
+_ = space:create_index('sk', {parts = {{2, 'unsigned', is_nullable = true}}})
+---
+...
+c = net:connect(box.cfg.listen)
+---
+...
+c.space.test.index.sk.parts
+---
+- - type: unsigned
+    is_nullable: true
+    fieldno: 2
+...
+space:drop()
+---
+...
+space = box.schema.create_space('test')
+---
+...
+c:close()
+---
+...
+box.schema.user.grant('guest', 'read', 'space', 'test')
+---
+...
+c = net:connect(box.cfg.listen)
+---
+...
+box.internal.collation.create('test', 'ICU', 'ru-RU')
+---
+...
+collation_id = box.internal.collation.id_by_name('test')
+---
+...
+_ = space:create_index('sk', { type = 'tree', parts = {{1, 'str', collation = 'test'}}, unique = true })
+---
+...
+c:reload_schema()
+---
+...
+parts = c.space.test.index.sk.parts
+---
+...
+#parts == 1
+---
+- true
+...
+parts[1].fieldno == 1
+---
+- true
+...
+parts[1].type == 'string'
+---
+- true
+...
+parts[1].is_nullable == false
+---
+- true
+...
+if _TARANTOOL >= '2.2.1' then                    \
+    return parts[1].collation == 'test'          \
+else                                             \
+    return parts[1].collation_id == collation_id \
+end
+---
+- true
+...
+c:close()
+---
+...
+box.internal.collation.drop('test')
+---
+...
+space:drop()
+---
+...
+c.state
+---
+- closed
+...
+c = nil
+---
+...
diff --git a/test/box/net.box_is_nullable_gh-3256.test.lua b/test/box/net.box_is_nullable_gh-3256.test.lua
new file mode 100644
index 000000000..3c5ee3971
--- /dev/null
+++ b/test/box/net.box_is_nullable_gh-3256.test.lua
@@ -0,0 +1,36 @@
+net = require('net.box')
+
+--
+-- gh-3256 net.box is_nullable and collation options output
+--
+space = box.schema.create_space('test')
+box.schema.user.grant('guest', 'read', 'space', 'test')
+_ = space:create_index('pk')
+_ = space:create_index('sk', {parts = {{2, 'unsigned', is_nullable = true}}})
+c = net:connect(box.cfg.listen)
+c.space.test.index.sk.parts
+space:drop()
+
+space = box.schema.create_space('test')
+c:close()
+box.schema.user.grant('guest', 'read', 'space', 'test')
+c = net:connect(box.cfg.listen)
+box.internal.collation.create('test', 'ICU', 'ru-RU')
+collation_id = box.internal.collation.id_by_name('test')
+_ = space:create_index('sk', { type = 'tree', parts = {{1, 'str', collation = 'test'}}, unique = true })
+c:reload_schema()
+parts = c.space.test.index.sk.parts
+#parts == 1
+parts[1].fieldno == 1
+parts[1].type == 'string'
+parts[1].is_nullable == false
+if _TARANTOOL >= '2.2.1' then                    \
+    return parts[1].collation == 'test'          \
+else                                             \
+    return parts[1].collation_id == collation_id \
+end
+c:close()
+box.internal.collation.drop('test')
+space:drop()
+c.state
+c = nil
diff --git a/test/box/net.box_leaks_gh-3629.result b/test/box/net.box_leaks_gh-3629.result
new file mode 100644
index 000000000..4c6688bf2
--- /dev/null
+++ b/test/box/net.box_leaks_gh-3629.result
@@ -0,0 +1,51 @@
+fiber = require 'fiber'
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-3629: netbox leaks when a connection is closed deliberately
+-- and it has non-finished requests.
+--
+ready = false
+---
+...
+ok = nil
+---
+...
+err = nil
+---
+...
+c = net:connect(box.cfg.listen)
+---
+...
+function do_long() while not ready do fiber.sleep(0.01) end end
+---
+...
+box.schema.func.create('do_long')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'do_long')
+---
+...
+f = fiber.create(function() ok, err = pcall(c.call, c, 'do_long') end)
+---
+...
+while f:status() ~= 'suspended' do fiber.sleep(0.01) end
+---
+...
+c:close()
+---
+...
+ready = true
+---
+...
+while not err do fiber.sleep(0.01) end
+---
+...
+ok, err
+---
+- false
+- Connection closed
+...
diff --git a/test/box/net.box_leaks_gh-3629.test.lua b/test/box/net.box_leaks_gh-3629.test.lua
new file mode 100644
index 000000000..03b5a2327
--- /dev/null
+++ b/test/box/net.box_leaks_gh-3629.test.lua
@@ -0,0 +1,20 @@
+fiber = require 'fiber'
+net = require('net.box')
+
+--
+-- gh-3629: netbox leaks when a connection is closed deliberately
+-- and it has non-finished requests.
+--
+ready = false
+ok = nil
+err = nil
+c = net:connect(box.cfg.listen)
+function do_long() while not ready do fiber.sleep(0.01) end end
+box.schema.func.create('do_long')
+box.schema.user.grant('guest', 'execute', 'function', 'do_long')
+f = fiber.create(function() ok, err = pcall(c.call, c, 'do_long') end)
+while f:status() ~= 'suspended' do fiber.sleep(0.01) end
+c:close()
+ready = true
+while not err do fiber.sleep(0.01) end
+ok, err
diff --git a/test/box/net.box_log_corrupted_rows_gh-4040.result b/test/box/net.box_log_corrupted_rows_gh-4040.result
new file mode 100644
index 000000000..603de0f13
--- /dev/null
+++ b/test/box/net.box_log_corrupted_rows_gh-4040.result
@@ -0,0 +1,72 @@
+test_run = require('test_run').new()
+---
+...
+socket = require('socket');
+---
+...
+LISTEN = require('uri').parse(box.cfg.listen)
+---
+...
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+---
+- true
+...
+--
+-- related to gh-4040: log corrupted rows
+--
+log_level = box.cfg.log_level
+---
+...
+box.cfg{log_level=6}
+---
+...
+sock = socket.tcp_connect(LISTEN.host, LISTEN.service)
+---
+...
+sock:read(9)
+---
+- Tarantool
+...
+-- we need to have a packet with correctly encoded length,
+-- so that it bypasses iproto length check, but cannot be
+-- decoded in xrow_header_decode
+-- 0x3C = 60, sha1 digest is 20 bytes long
+data = string.fromhex('3C'..string.rep(require('digest').sha1_hex('bcde'), 3))
+---
+...
+sock:write(data)
+---
+- 61
+...
+sock:close()
+---
+- true
+...
+test_run:wait_log('default', 'Got a corrupted row.*', nil, 10)
+---
+- 'Got a corrupted row:'
+...
+test_run:wait_log('default', '00000000:.*', nil, 10)
+---
+- '00000000: A3 02 D6 5A E4 D9 E7 68 A1 53 8D 53 60 5F 20 3F '
+...
+test_run:wait_log('default', '00000010:.*', nil, 10)
+---
+- '00000010: D8 E2 D6 E2 A3 02 D6 5A E4 D9 E7 68 A1 53 8D 53 '
+...
+test_run:wait_log('default', '00000020:.*', nil, 10)
+---
+- '00000020: 60 5F 20 3F D8 E2 D6 E2 A3 02 D6 5A E4 D9 E7 68 '
+...
+test_run:wait_log('default', '00000030:.*', nil, 10)
+---
+- '00000030: A1 53 8D 53 60 5F 20 3F D8 E2 D6 E2 '
+...
+-- we expect nothing below, so don't wait
+test_run:grep_log('default', '00000040:.*')
+---
+- null
+...
+box.cfg{log_level=log_level}
+---
+...
diff --git a/test/box/net.box_log_corrupted_rows_gh-4040.test.lua b/test/box/net.box_log_corrupted_rows_gh-4040.test.lua
new file mode 100644
index 000000000..a30b4a254
--- /dev/null
+++ b/test/box/net.box_log_corrupted_rows_gh-4040.test.lua
@@ -0,0 +1,31 @@
+test_run = require('test_run').new()
+socket = require('socket');
+
+LISTEN = require('uri').parse(box.cfg.listen)
+
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+
+--
+-- related to gh-4040: log corrupted rows
+--
+log_level = box.cfg.log_level
+box.cfg{log_level=6}
+sock = socket.tcp_connect(LISTEN.host, LISTEN.service)
+sock:read(9)
+-- we need to have a packet with correctly encoded length,
+-- so that it bypasses iproto length check, but cannot be
+-- decoded in xrow_header_decode
+-- 0x3C = 60, sha1 digest is 20 bytes long
+data = string.fromhex('3C'..string.rep(require('digest').sha1_hex('bcde'), 3))
+sock:write(data)
+sock:close()
+
+test_run:wait_log('default', 'Got a corrupted row.*', nil, 10)
+test_run:wait_log('default', '00000000:.*', nil, 10)
+test_run:wait_log('default', '00000010:.*', nil, 10)
+test_run:wait_log('default', '00000020:.*', nil, 10)
+test_run:wait_log('default', '00000030:.*', nil, 10)
+-- we expect nothing below, so don't wait
+test_run:grep_log('default', '00000040:.*')
+
+box.cfg{log_level=log_level}
diff --git a/test/box/net.box_long-poll_input_gh-3400.result b/test/box/net.box_long-poll_input_gh-3400.result
new file mode 100644
index 000000000..062bd563a
--- /dev/null
+++ b/test/box/net.box_long-poll_input_gh-3400.result
@@ -0,0 +1,35 @@
+fiber = require 'fiber'
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-3400: long-poll input discard must not touch event loop of
+-- a closed connection.
+--
+function long() fiber.yield() return 100 end
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+c:ping()
+---
+- true
+...
+-- Create batch of two requests. First request is sent to TX
+-- thread, second one terminates connection. The preceeding
+-- request discards input, and this operation must not trigger
+-- new attempts to read any data - the connection is closed
+-- already.
+--
+f = fiber.create(c._transport.perform_request, nil, nil, false, 'call_17', nil, nil, nil, 'long', {}) c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80')
+---
+...
+while f:status() ~= 'dead' do fiber.sleep(0.01) end
+---
+...
+c:close()
+---
+...
diff --git a/test/box/net.box_long-poll_input_gh-3400.test.lua b/test/box/net.box_long-poll_input_gh-3400.test.lua
new file mode 100644
index 000000000..bc9db1e69
--- /dev/null
+++ b/test/box/net.box_long-poll_input_gh-3400.test.lua
@@ -0,0 +1,19 @@
+fiber = require 'fiber'
+net = require('net.box')
+
+--
+-- gh-3400: long-poll input discard must not touch event loop of
+-- a closed connection.
+--
+function long() fiber.yield() return 100 end
+c = net.connect(box.cfg.listen)
+c:ping()
+-- Create batch of two requests. First request is sent to TX
+-- thread, second one terminates connection. The preceeding
+-- request discards input, and this operation must not trigger
+-- new attempts to read any data - the connection is closed
+-- already.
+--
+f = fiber.create(c._transport.perform_request, nil, nil, false, 'call_17', nil, nil, nil, 'long', {}) c._transport.perform_request(nil, nil, false, 'inject', nil, nil, nil, '\x80')
+while f:status() ~= 'dead' do fiber.sleep(0.01) end
+c:close()
diff --git a/test/box/net.box_methods_gh-3107.result b/test/box/net.box_methods_gh-3107.result
new file mode 100644
index 000000000..8ff69ebd6
--- /dev/null
+++ b/test/box/net.box_methods_gh-3107.result
@@ -0,0 +1,277 @@
+fiber = require 'fiber'
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+---
+...
+box.schema.func.create('long_function')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+---
+...
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+---
+...
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+---
+...
+s = box.schema.create_space('test')
+---
+...
+pk = s:create_index('pk')
+---
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{2}
+---
+- [2]
+...
+s:replace{3}
+---
+- [3]
+...
+s:replace{4}
+---
+- [4]
+...
+c = net:connect(box.cfg.listen)
+---
+...
+--
+-- Ensure a request can be finalized from non-caller fibers.
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+---
+...
+ret = {}
+---
+...
+count = 0
+---
+...
+for i = 1, 10 do fiber.create(function() ret[i] = future:wait_result(1000) count = count + 1 end) end
+---
+...
+future:wait_result(0.01) -- Must fail on timeout.
+---
+- null
+- Timeout exceeded
+...
+finalize_long()
+---
+...
+while count ~= 10 do fiber.sleep(0.1) end
+---
+...
+ret
+---
+- - &0 [1, 2, 3]
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+...
+--
+-- Test space methods.
+--
+c:close()
+---
+...
+box.schema.user.grant('guest', 'read,write', 'space', 'test')
+---
+...
+c = net:connect(box.cfg.listen)
+---
+...
+future = c.space.test:select({1}, {is_async = true})
+---
+...
+ret = future:wait_result(100)
+---
+...
+ret
+---
+- - [1]
+...
+type(ret[1])
+---
+- cdata
+...
+future = c.space.test:insert({5}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- [5]
+...
+s:get{5}
+---
+- [5]
+...
+future = c.space.test:replace({6}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- [6]
+...
+s:get{6}
+---
+- [6]
+...
+future = c.space.test:delete({6}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- [6]
+...
+s:get{6}
+---
+...
+future = c.space.test:update({5}, {{'=', 2, 5}}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- [5, 5]
+...
+s:get{5}
+---
+- [5, 5]
+...
+future = c.space.test:upsert({5}, {{'=', 2, 6}}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- null
+...
+s:get{5}
+---
+- [5, 6]
+...
+future = c.space.test:get({5}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- [5, 6]
+...
+--
+-- Test index methods.
+--
+future = c.space.test.index.pk:select({1}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- - [1]
+...
+future = c.space.test.index.pk:get({2}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- [2]
+...
+future = c.space.test.index.pk:min({}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- [1]
+...
+future = c.space.test.index.pk:max({}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- [5, 6]
+...
+c:close()
+---
+...
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+c = net:connect(box.cfg.listen)
+---
+...
+future = c.space.test.index.pk:count({3}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- 1
+...
+c:close()
+---
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
+c = net:connect(box.cfg.listen)
+---
+...
+future = c.space.test.index.pk:delete({3}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- [3]
+...
+s:get{3}
+---
+...
+future = c.space.test.index.pk:update({4}, {{'=', 2, 6}}, {is_async = true})
+---
+...
+future:wait_result(100)
+---
+- [4, 6]
+...
+s:get{4}
+---
+- [4, 6]
+...
+--
+-- Test async errors.
+--
+future = c.space.test:insert({1}, {is_async = true})
+---
+...
+future:wait_result()
+---
+- null
+- Duplicate key exists in unique index 'pk' in space 'test'
+...
+future:result()
+---
+- null
+- Duplicate key exists in unique index 'pk' in space 'test'
+...
+box.schema.func.drop('long_function')
+---
+...
+c:close()
+---
+...
+s:drop()
+---
+...
diff --git a/test/box/net.box_methods_gh-3107.test.lua b/test/box/net.box_methods_gh-3107.test.lua
new file mode 100644
index 000000000..364a72ed3
--- /dev/null
+++ b/test/box/net.box_methods_gh-3107.test.lua
@@ -0,0 +1,96 @@
+fiber = require 'fiber'
+net = require('net.box')
+
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+box.schema.func.create('long_function')
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+s = box.schema.create_space('test')
+pk = s:create_index('pk')
+s:replace{1}
+s:replace{2}
+s:replace{3}
+s:replace{4}
+c = net:connect(box.cfg.listen)
+
+--
+-- Ensure a request can be finalized from non-caller fibers.
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+ret = {}
+count = 0
+for i = 1, 10 do fiber.create(function() ret[i] = future:wait_result(1000) count = count + 1 end) end
+future:wait_result(0.01) -- Must fail on timeout.
+finalize_long()
+while count ~= 10 do fiber.sleep(0.1) end
+ret
+
+--
+-- Test space methods.
+--
+c:close()
+box.schema.user.grant('guest', 'read,write', 'space', 'test')
+c = net:connect(box.cfg.listen)
+future = c.space.test:select({1}, {is_async = true})
+ret = future:wait_result(100)
+ret
+type(ret[1])
+future = c.space.test:insert({5}, {is_async = true})
+future:wait_result(100)
+s:get{5}
+future = c.space.test:replace({6}, {is_async = true})
+future:wait_result(100)
+s:get{6}
+future = c.space.test:delete({6}, {is_async = true})
+future:wait_result(100)
+s:get{6}
+future = c.space.test:update({5}, {{'=', 2, 5}}, {is_async = true})
+future:wait_result(100)
+s:get{5}
+future = c.space.test:upsert({5}, {{'=', 2, 6}}, {is_async = true})
+future:wait_result(100)
+s:get{5}
+future = c.space.test:get({5}, {is_async = true})
+future:wait_result(100)
+
+--
+-- Test index methods.
+--
+future = c.space.test.index.pk:select({1}, {is_async = true})
+future:wait_result(100)
+future = c.space.test.index.pk:get({2}, {is_async = true})
+future:wait_result(100)
+future = c.space.test.index.pk:min({}, {is_async = true})
+future:wait_result(100)
+future = c.space.test.index.pk:max({}, {is_async = true})
+future:wait_result(100)
+c:close()
+box.schema.user.grant('guest', 'execute', 'universe')
+c = net:connect(box.cfg.listen)
+future = c.space.test.index.pk:count({3}, {is_async = true})
+future:wait_result(100)
+c:close()
+box.schema.user.revoke('guest', 'execute', 'universe')
+c = net:connect(box.cfg.listen)
+future = c.space.test.index.pk:delete({3}, {is_async = true})
+future:wait_result(100)
+s:get{3}
+future = c.space.test.index.pk:update({4}, {{'=', 2, 6}}, {is_async = true})
+future:wait_result(100)
+s:get{4}
+
+--
+-- Test async errors.
+--
+future = c.space.test:insert({1}, {is_async = true})
+future:wait_result()
+future:result()
+
+box.schema.func.drop('long_function')
+
+c:close()
+s:drop()
diff --git a/test/box/net.box_msgpack_gh-2195.result b/test/box/net.box_msgpack_gh-2195.result
new file mode 100644
index 000000000..a4c851334
--- /dev/null
+++ b/test/box/net.box_msgpack_gh-2195.result
@@ -0,0 +1,527 @@
+msgpack = require 'msgpack'
+---
+...
+test_run = require('test_run').new()
+---
+...
+test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '")
+---
+- true
+...
+net = require('net.box')
+---
+...
+-- CALL vs CALL_16 in connect options
+function echo(...) return ... end
+---
+...
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+c:call('echo', {42})
+---
+- 42
+...
+c:eval('return echo(...)', {42})
+---
+- 42
+...
+-- invalid arguments
+c:call('echo', 42)
+---
+- error: 'builtin/box/net_box.lua..."]:<line>: Use remote:call(func_name, {arg1, arg2, ...},
+    opts) instead of remote:call(func_name, arg1, arg2, ...)'
+...
+c:eval('return echo(...)', 42)
+---
+- error: 'builtin/box/net_box.lua..."]:<line>: Use remote:eval(expression, {arg1, arg2, ...},
+    opts) instead of remote:eval(expression, arg1, arg2, ...)'
+...
+c:close()
+---
+...
+c = net.connect(box.cfg.listen, {call_16 = true})
+---
+...
+c:call('echo', 42)
+---
+- - [42]
+...
+c:eval('return echo(...)', 42)
+---
+- 42
+...
+c:close()
+---
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
+--
+-- gh-2195 export pure msgpack from net.box
+--
+space = box.schema.space.create('test')
+---
+...
+_ = box.space.test:create_index('primary')
+---
+...
+box.schema.user.grant('guest', 'read,write', 'space', 'test')
+---
+...
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+ibuf = require('buffer').ibuf()
+---
+...
+c:ping()
+---
+- true
+...
+c.space.test ~= nil
+---
+- true
+...
+c.space.test:replace({1, 'hello'})
+---
+- [1, 'hello']
+...
+-- replace
+c.space.test:replace({2}, {buffer = ibuf})
+---
+- 9
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: [[2]]}
+...
+-- replace + skip_header
+c.space.test:replace({2}, {buffer = ibuf, skip_header = true})
+---
+- 7
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- [[2]]
+...
+-- insert
+c.space.test:insert({3}, {buffer = ibuf})
+---
+- 9
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: [[3]]}
+...
+-- insert + skip_header
+_ = space:delete({3})
+---
+...
+c.space.test:insert({3}, {buffer = ibuf, skip_header = true})
+---
+- 7
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- [[3]]
+...
+-- update
+c.space.test:update({3}, {}, {buffer = ibuf})
+---
+- 9
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: [[3]]}
+...
+c.space.test.index.primary:update({3}, {}, {buffer = ibuf})
+---
+- 9
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: [[3]]}
+...
+-- update + skip_header
+c.space.test:update({3}, {}, {buffer = ibuf, skip_header = true})
+---
+- 7
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- [[3]]
+...
+c.space.test.index.primary:update({3}, {}, {buffer = ibuf, skip_header = true})
+---
+- 7
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- [[3]]
+...
+-- upsert
+c.space.test:upsert({4}, {}, {buffer = ibuf})
+---
+- 7
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: []}
+...
+-- upsert + skip_header
+c.space.test:upsert({4}, {}, {buffer = ibuf, skip_header = true})
+---
+- 5
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- []
+...
+-- delete
+c.space.test:upsert({4}, {}, {buffer = ibuf})
+---
+- 7
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: []}
+...
+-- delete + skip_header
+c.space.test:upsert({4}, {}, {buffer = ibuf, skip_header = true})
+---
+- 5
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- []
+...
+-- select
+c.space.test.index.primary:select({3}, {iterator = 'LE', buffer = ibuf})
+---
+- 19
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: [[3], [2], [1, 'hello']]}
+...
+-- select + skip_header
+c.space.test.index.primary:select({3}, {iterator = 'LE', buffer = ibuf, skip_header = true})
+---
+- 17
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- [[3], [2], [1, 'hello']]
+...
+-- select
+len = c.space.test:select({}, {buffer = ibuf})
+---
+...
+ibuf.rpos + len == ibuf.wpos
+---
+- true
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+ibuf.rpos == ibuf.wpos
+---
+- true
+...
+len
+---
+- 21
+...
+result
+---
+- {48: [[1, 'hello'], [2], [3], [4]]}
+...
+-- select + skip_header
+len = c.space.test:select({}, {buffer = ibuf, skip_header = true})
+---
+...
+ibuf.rpos + len == ibuf.wpos
+---
+- true
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+ibuf.rpos == ibuf.wpos
+---
+- true
+...
+len
+---
+- 19
+...
+result
+---
+- [[1, 'hello'], [2], [3], [4]]
+...
+-- call
+c:call("echo", {1, 2, 3}, {buffer = ibuf})
+---
+- 10
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: [1, 2, 3]}
+...
+c:call("echo", {}, {buffer = ibuf})
+---
+- 7
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: []}
+...
+c:call("echo", nil, {buffer = ibuf})
+---
+- 7
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: []}
+...
+-- call + skip_header
+c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
+---
+- 8
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- [1, 2, 3]
+...
+c:call("echo", {}, {buffer = ibuf, skip_header = true})
+---
+- 5
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- []
+...
+c:call("echo", nil, {buffer = ibuf, skip_header = true})
+---
+- 5
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- []
+...
+-- eval
+c:eval("echo(...)", {1, 2, 3}, {buffer = ibuf})
+---
+- 7
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: []}
+...
+c:eval("echo(...)", {}, {buffer = ibuf})
+---
+- 7
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: []}
+...
+c:eval("echo(...)", nil, {buffer = ibuf})
+---
+- 7
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: []}
+...
+-- eval + skip_header
+c:eval("echo(...)", {1, 2, 3}, {buffer = ibuf, skip_header = true})
+---
+- 5
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- []
+...
+c:eval("echo(...)", {}, {buffer = ibuf, skip_header = true})
+---
+- 5
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- []
+...
+c:eval("echo(...)", nil, {buffer = ibuf, skip_header = true})
+---
+- 5
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- []
+...
+-- make several request into a buffer with skip_header, then read
+-- results
+c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
+---
+- 8
+...
+c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
+---
+- 8
+...
+c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
+---
+- 8
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- [1, 2, 3]
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- [1, 2, 3]
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- [1, 2, 3]
+...
+-- unsupported methods
+c.space.test:get({1}, { buffer = ibuf})
+---
+- error: 'builtin/box/net_box.lua..."]:<line>: index:get() doesn''t support `buffer` argument'
+...
+c.space.test.index.primary:min({}, { buffer = ibuf})
+---
+- error: 'builtin/box/net_box.lua..."]:<line>: index:min() doesn''t support `buffer` argument'
+...
+c.space.test.index.primary:max({}, { buffer = ibuf})
+---
+- error: 'builtin/box/net_box.lua..."]:<line>: index:max() doesn''t support `buffer` argument'
+...
+c.space.test.index.primary:count({}, { buffer = ibuf})
+---
+- error: 'builtin/box/net_box.lua..."]:<line>: index:count() doesn''t support `buffer` argument'
+...
+c.space.test.index.primary:get({1}, { buffer = ibuf})
+---
+- error: 'builtin/box/net_box.lua..."]:<line>: index:get() doesn''t support `buffer` argument'
+...
+-- error handling
+rpos, wpos = ibuf.rpos, ibuf.wpos
+---
+...
+c.space.test:insert({1}, {buffer = ibuf})
+---
+- error: Duplicate key exists in unique index 'primary' in space 'test'
+...
+ibuf.rpos == rpos, ibuf.wpos == wpos
+---
+- true
+- true
+...
+ibuf = nil
+---
+...
+c:close()
+---
+...
+space:drop()
+---
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
diff --git a/test/box/net.box_msgpack_gh-2195.test.lua b/test/box/net.box_msgpack_gh-2195.test.lua
new file mode 100644
index 000000000..8c14b4b43
--- /dev/null
+++ b/test/box/net.box_msgpack_gh-2195.test.lua
@@ -0,0 +1,192 @@
+msgpack = require 'msgpack'
+test_run = require('test_run').new()
+test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '")
+net = require('net.box')
+
+-- CALL vs CALL_16 in connect options
+function echo(...) return ... end
+box.schema.user.grant('guest', 'execute', 'universe')
+c = net.connect(box.cfg.listen)
+c:call('echo', {42})
+c:eval('return echo(...)', {42})
+-- invalid arguments
+c:call('echo', 42)
+c:eval('return echo(...)', 42)
+c:close()
+c = net.connect(box.cfg.listen, {call_16 = true})
+c:call('echo', 42)
+c:eval('return echo(...)', 42)
+c:close()
+box.schema.user.revoke('guest', 'execute', 'universe')
+
+--
+-- gh-2195 export pure msgpack from net.box
+--
+
+space = box.schema.space.create('test')
+_ = box.space.test:create_index('primary')
+box.schema.user.grant('guest', 'read,write', 'space', 'test')
+box.schema.user.grant('guest', 'execute', 'universe')
+c = net.connect(box.cfg.listen)
+ibuf = require('buffer').ibuf()
+
+c:ping()
+c.space.test ~= nil
+
+c.space.test:replace({1, 'hello'})
+
+-- replace
+c.space.test:replace({2}, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- replace + skip_header
+c.space.test:replace({2}, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- insert
+c.space.test:insert({3}, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- insert + skip_header
+_ = space:delete({3})
+c.space.test:insert({3}, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- update
+c.space.test:update({3}, {}, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+c.space.test.index.primary:update({3}, {}, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- update + skip_header
+c.space.test:update({3}, {}, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+c.space.test.index.primary:update({3}, {}, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- upsert
+c.space.test:upsert({4}, {}, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- upsert + skip_header
+c.space.test:upsert({4}, {}, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- delete
+c.space.test:upsert({4}, {}, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- delete + skip_header
+c.space.test:upsert({4}, {}, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- select
+c.space.test.index.primary:select({3}, {iterator = 'LE', buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- select + skip_header
+c.space.test.index.primary:select({3}, {iterator = 'LE', buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- select
+len = c.space.test:select({}, {buffer = ibuf})
+ibuf.rpos + len == ibuf.wpos
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+ibuf.rpos == ibuf.wpos
+len
+result
+
+-- select + skip_header
+len = c.space.test:select({}, {buffer = ibuf, skip_header = true})
+ibuf.rpos + len == ibuf.wpos
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+ibuf.rpos == ibuf.wpos
+len
+result
+
+-- call
+c:call("echo", {1, 2, 3}, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+c:call("echo", {}, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+c:call("echo", nil, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- call + skip_header
+c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+c:call("echo", {}, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+c:call("echo", nil, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- eval
+c:eval("echo(...)", {1, 2, 3}, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+c:eval("echo(...)", {}, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+c:eval("echo(...)", nil, {buffer = ibuf})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- eval + skip_header
+c:eval("echo(...)", {1, 2, 3}, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+c:eval("echo(...)", {}, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+c:eval("echo(...)", nil, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- make several request into a buffer with skip_header, then read
+-- results
+c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
+c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
+c:call("echo", {1, 2, 3}, {buffer = ibuf, skip_header = true})
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+-- unsupported methods
+c.space.test:get({1}, { buffer = ibuf})
+c.space.test.index.primary:min({}, { buffer = ibuf})
+c.space.test.index.primary:max({}, { buffer = ibuf})
+c.space.test.index.primary:count({}, { buffer = ibuf})
+c.space.test.index.primary:get({1}, { buffer = ibuf})
+
+-- error handling
+rpos, wpos = ibuf.rpos, ibuf.wpos
+c.space.test:insert({1}, {buffer = ibuf})
+ibuf.rpos == rpos, ibuf.wpos == wpos
+
+ibuf = nil
+c:close()
+space:drop()
+box.schema.user.revoke('guest', 'execute', 'universe')
diff --git a/test/box/net.box_on_schema_reload-gh-1904.result b/test/box/net.box_on_schema_reload-gh-1904.result
new file mode 100644
index 000000000..5029684bf
--- /dev/null
+++ b/test/box/net.box_on_schema_reload-gh-1904.result
@@ -0,0 +1,102 @@
+fiber = require 'fiber'
+---
+...
+test_run = require('test_run').new()
+---
+...
+LISTEN = require('uri').parse(box.cfg.listen)
+---
+...
+space = box.schema.space.create('net_box_test_space')
+---
+...
+index = space:create_index('primary', { type = 'tree' })
+---
+...
+box.schema.user.create('netbox', { password  = 'test' })
+---
+...
+box.schema.user.grant('netbox', 'read,write', 'space', 'net_box_test_space')
+---
+...
+box.schema.user.grant('netbox', 'execute', 'universe')
+---
+...
+net = require('net.box')
+---
+...
+-- gh-1904 net.box hangs in :close() if a fiber was cancelled
+-- while blocked in :_wait_state() in :_request()
+options = {user = 'netbox', password = 'badpass', wait_connected = false, reconnect_after = 0.01}
+---
+...
+c = net:new(box.cfg.listen, options)
+---
+...
+f = fiber.create(function() c:call("") end)
+---
+...
+fiber.sleep(0.01)
+---
+...
+f:cancel(); c:close()
+---
+...
+box.schema.user.grant('guest', 'read', 'space', '_schema')
+---
+...
+-- check for on_schema_reload callback
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+do
+    local a = 0
+    function osr_cb()
+        a = a + 1
+    end
+    local con = net.new(box.cfg.listen, {
+        wait_connected = false
+    })
+    con:on_schema_reload(osr_cb)
+    con:wait_connected()
+    con.space._schema:select{}
+    box.schema.space.create('misisipi')
+    box.space.misisipi:drop()
+    con.space._schema:select{}
+    con:close()
+    con = nil
+
+    return a
+end;
+---
+- 2
+...
+do
+    local a = 0
+    function osr_cb()
+        a = a + 1
+    end
+    local con = net.new(box.cfg.listen, {
+        wait_connected = true
+    })
+    con:on_schema_reload(osr_cb)
+    con.space._schema:select{}
+    box.schema.space.create('misisipi')
+    box.space.misisipi:drop()
+    con.space._schema:select{}
+    con:close()
+    con = nil
+
+    return a
+end;
+---
+- 1
+...
+test_run:cmd("setopt delimiter ''");
+---
+- true
+...
+box.schema.user.revoke('guest', 'read', 'space', '_schema')
+---
+...
diff --git a/test/box/net.box_on_schema_reload-gh-1904.test.lua b/test/box/net.box_on_schema_reload-gh-1904.test.lua
new file mode 100644
index 000000000..eeb9def65
--- /dev/null
+++ b/test/box/net.box_on_schema_reload-gh-1904.test.lua
@@ -0,0 +1,65 @@
+fiber = require 'fiber'
+test_run = require('test_run').new()
+
+LISTEN = require('uri').parse(box.cfg.listen)
+space = box.schema.space.create('net_box_test_space')
+index = space:create_index('primary', { type = 'tree' })
+
+box.schema.user.create('netbox', { password  = 'test' })
+box.schema.user.grant('netbox', 'read,write', 'space', 'net_box_test_space')
+box.schema.user.grant('netbox', 'execute', 'universe')
+
+net = require('net.box')
+
+-- gh-1904 net.box hangs in :close() if a fiber was cancelled
+-- while blocked in :_wait_state() in :_request()
+options = {user = 'netbox', password = 'badpass', wait_connected = false, reconnect_after = 0.01}
+c = net:new(box.cfg.listen, options)
+f = fiber.create(function() c:call("") end)
+fiber.sleep(0.01)
+f:cancel(); c:close()
+
+box.schema.user.grant('guest', 'read', 'space', '_schema')
+
+-- check for on_schema_reload callback
+test_run:cmd("setopt delimiter ';'")
+do
+    local a = 0
+    function osr_cb()
+        a = a + 1
+    end
+    local con = net.new(box.cfg.listen, {
+        wait_connected = false
+    })
+    con:on_schema_reload(osr_cb)
+    con:wait_connected()
+    con.space._schema:select{}
+    box.schema.space.create('misisipi')
+    box.space.misisipi:drop()
+    con.space._schema:select{}
+    con:close()
+    con = nil
+
+    return a
+end;
+do
+    local a = 0
+    function osr_cb()
+        a = a + 1
+    end
+    local con = net.new(box.cfg.listen, {
+        wait_connected = true
+    })
+    con:on_schema_reload(osr_cb)
+    con.space._schema:select{}
+    box.schema.space.create('misisipi')
+    box.space.misisipi:drop()
+    con.space._schema:select{}
+    con:close()
+    con = nil
+
+    return a
+end;
+test_run:cmd("setopt delimiter ''");
+
+box.schema.user.revoke('guest', 'read', 'space', '_schema')
diff --git a/test/box/net.box_password_gh-1545.result b/test/box/net.box_password_gh-1545.result
new file mode 100644
index 000000000..984084cae
--- /dev/null
+++ b/test/box/net.box_password_gh-1545.result
@@ -0,0 +1,28 @@
+remote = require 'net.box'
+---
+...
+LISTEN = require('uri').parse(box.cfg.listen)
+---
+...
+-- #1545 empty password
+cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'test' })
+---
+...
+cn ~= nil
+---
+- true
+...
+cn:close()
+---
+...
+cn = remote.connect(LISTEN.host, LISTEN.service, { password = 'test' })
+---
+- error: 'net.box: user is not defined'
+...
+cn ~= nil
+---
+- true
+...
+cn:close()
+---
+...
diff --git a/test/box/net.box_password_gh-1545.test.lua b/test/box/net.box_password_gh-1545.test.lua
new file mode 100644
index 000000000..86d496432
--- /dev/null
+++ b/test/box/net.box_password_gh-1545.test.lua
@@ -0,0 +1,10 @@
+remote = require 'net.box'
+LISTEN = require('uri').parse(box.cfg.listen)
+
+-- #1545 empty password
+cn = remote.connect(LISTEN.host, LISTEN.service, { user = 'test' })
+cn ~= nil
+cn:close()
+cn = remote.connect(LISTEN.host, LISTEN.service, { password = 'test' })
+cn ~= nil
+cn:close()
diff --git a/test/box/net.box_permissions.result b/test/box/net.box_permissions.result
new file mode 100644
index 000000000..04729dccb
--- /dev/null
+++ b/test/box/net.box_permissions.result
@@ -0,0 +1,186 @@
+remote = require 'net.box'
+---
+...
+fiber = require 'fiber'
+---
+...
+log = require 'log'
+---
+...
+LISTEN = require('uri').parse(box.cfg.listen)
+---
+...
+space = box.schema.space.create('net_box_test_space')
+---
+...
+index = space:create_index('primary', { type = 'tree' })
+---
+...
+-- low level connection
+log.info("create connection")
+---
+...
+cn = remote.connect(LISTEN.host, LISTEN.service)
+---
+...
+log.info("state is %s", cn.state)
+---
+...
+cn:ping()
+---
+- true
+...
+log.info("ping is done")
+---
+...
+cn:ping()
+---
+- true
+...
+log.info("ping is done")
+---
+...
+cn:ping()
+---
+- true
+...
+-- check permissions
+cn:call('unexists_procedure')
+---
+- error: Execute access to function 'unexists_procedure' is denied for user 'guest'
+...
+function test_foo(a,b,c) return { {{ [a] = 1 }}, {{ [b] = 2 }}, c } end
+---
+...
+cn:call('test_foo', {'a', 'b', 'c'})
+---
+- error: Execute access to function 'test_foo' is denied for user 'guest'
+...
+cn:eval('return 2+2')
+---
+- error: Execute access to universe '' is denied for user 'guest'
+...
+cn:close()
+---
+...
+-- connect and call without usage access
+box.schema.user.grant('guest','execute','universe')
+---
+...
+box.schema.user.revoke('guest','usage','universe')
+---
+...
+box.session.su("guest")
+---
+...
+cn = remote.connect(LISTEN.host, LISTEN.service)
+---
+...
+cn:call('test_foo', {'a', 'b', 'c'})
+---
+- error: Usage access to universe '' is denied for user 'guest'
+...
+box.session.su("admin")
+---
+...
+box.schema.user.grant('guest','usage','universe')
+---
+...
+cn:close()
+---
+...
+cn = remote.connect(box.cfg.listen)
+---
+...
+cn:call('unexists_procedure')
+---
+- error: Procedure 'unexists_procedure' is not defined
+...
+cn:call('test_foo', {'a', 'b', 'c'})
+---
+- [[{'a': 1}], [{'b': 2}], 'c']
+...
+cn:call(nil, {'a', 'b', 'c'})
+---
+- error: Procedure 'nil' is not defined
+...
+cn:eval('return 2+2')
+---
+- 4
+...
+cn:eval('return 1, 2, 3')
+---
+- 1
+- 2
+- 3
+...
+cn:eval('return ...', {1, 2, 3})
+---
+- 1
+- 2
+- 3
+...
+cn:eval('return { k = "v1" }, true, {  xx = 10, yy = 15 }, nil')
+---
+- {'k': 'v1'}
+- true
+- {'yy': 15, 'xx': 10}
+- null
+...
+cn:eval('return nil')
+---
+- null
+...
+cn:eval('return')
+---
+...
+cn:eval('error("exception")')
+---
+- error: 'eval:1: exception'
+...
+cn:eval('box.error(0)')
+---
+- error: Unknown error
+...
+cn:eval('!invalid expression')
+---
+- error: 'eval:1: unexpected symbol near ''!'''
+...
+-- box.commit() missing at return of CALL/EVAL
+function no_commit() box.begin() fiber.sleep(0.001) end
+---
+...
+cn:call('no_commit')
+---
+- error: Transaction is active at return from function
+...
+cn:eval('no_commit()')
+---
+- error: Transaction is active at return from function
+...
+remote.self:eval('return 1+1, 2+2')
+---
+- 2
+- 4
+...
+remote.self:eval('return')
+---
+...
+remote.self:eval('error("exception")')
+---
+- error: '[string "error("exception")"]:1: exception'
+...
+remote.self:eval('box.error(0)')
+---
+- error: Unknown error
+...
+remote.self:eval('!invalid expression')
+---
+- error: '[string "return !invalid expression"]:1: unexpected symbol near ''!'''
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
+cn:close()
+---
+...
diff --git a/test/box/net.box_permissions.test.lua b/test/box/net.box_permissions.test.lua
new file mode 100644
index 000000000..249604f64
--- /dev/null
+++ b/test/box/net.box_permissions.test.lua
@@ -0,0 +1,66 @@
+remote = require 'net.box'
+fiber = require 'fiber'
+log = require 'log'
+
+LISTEN = require('uri').parse(box.cfg.listen)
+space = box.schema.space.create('net_box_test_space')
+index = space:create_index('primary', { type = 'tree' })
+
+-- low level connection
+log.info("create connection")
+cn = remote.connect(LISTEN.host, LISTEN.service)
+log.info("state is %s", cn.state)
+
+cn:ping()
+log.info("ping is done")
+cn:ping()
+log.info("ping is done")
+
+
+cn:ping()
+
+
+-- check permissions
+cn:call('unexists_procedure')
+function test_foo(a,b,c) return { {{ [a] = 1 }}, {{ [b] = 2 }}, c } end
+cn:call('test_foo', {'a', 'b', 'c'})
+cn:eval('return 2+2')
+cn:close()
+-- connect and call without usage access
+box.schema.user.grant('guest','execute','universe')
+box.schema.user.revoke('guest','usage','universe')
+box.session.su("guest")
+cn = remote.connect(LISTEN.host, LISTEN.service)
+cn:call('test_foo', {'a', 'b', 'c'})
+box.session.su("admin")
+box.schema.user.grant('guest','usage','universe')
+cn:close()
+cn = remote.connect(box.cfg.listen)
+
+cn:call('unexists_procedure')
+cn:call('test_foo', {'a', 'b', 'c'})
+cn:call(nil, {'a', 'b', 'c'})
+cn:eval('return 2+2')
+cn:eval('return 1, 2, 3')
+cn:eval('return ...', {1, 2, 3})
+cn:eval('return { k = "v1" }, true, {  xx = 10, yy = 15 }, nil')
+cn:eval('return nil')
+cn:eval('return')
+cn:eval('error("exception")')
+cn:eval('box.error(0)')
+cn:eval('!invalid expression')
+
+-- box.commit() missing at return of CALL/EVAL
+function no_commit() box.begin() fiber.sleep(0.001) end
+cn:call('no_commit')
+cn:eval('no_commit()')
+
+remote.self:eval('return 1+1, 2+2')
+remote.self:eval('return')
+remote.self:eval('error("exception")')
+remote.self:eval('box.error(0)')
+remote.self:eval('!invalid expression')
+
+box.schema.user.revoke('guest', 'execute', 'universe')
+
+cn:close()
diff --git a/test/box/net.box_pseudo_objects_gh-2401.result b/test/box/net.box_pseudo_objects_gh-2401.result
new file mode 100644
index 000000000..46730368f
--- /dev/null
+++ b/test/box/net.box_pseudo_objects_gh-2401.result
@@ -0,0 +1,55 @@
+test_run = require('test_run').new()
+---
+...
+net = require('net.box')
+---
+...
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+---
+- true
+...
+--
+-- gh-2401 update pseudo objects not replace them
+--
+space = box.schema.space.create('test')
+---
+...
+box.schema.user.grant('guest', 'read', 'space', 'test')
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+cspace = c.space.test
+---
+...
+space.index.test_index == nil
+---
+- true
+...
+cspace.index.test_index == nil
+---
+- true
+...
+_ = space:create_index("test_index", {parts={1, 'string'}})
+---
+...
+c:reload_schema()
+---
+...
+space.index.test_index ~= nil
+---
+- true
+...
+cspace.index.test_index ~= nil
+---
+- true
+...
+c.space.test.index.test_index ~= nil
+---
+- true
+...
+-- cleanup
+space:drop()
+---
+...
diff --git a/test/box/net.box_pseudo_objects_gh-2401.test.lua b/test/box/net.box_pseudo_objects_gh-2401.test.lua
new file mode 100644
index 000000000..b9277ae94
--- /dev/null
+++ b/test/box/net.box_pseudo_objects_gh-2401.test.lua
@@ -0,0 +1,23 @@
+test_run = require('test_run').new()
+net = require('net.box')
+
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+
+--
+-- gh-2401 update pseudo objects not replace them
+--
+space = box.schema.space.create('test')
+box.schema.user.grant('guest', 'read', 'space', 'test')
+c = net.connect(box.cfg.listen)
+cspace = c.space.test
+space.index.test_index == nil
+cspace.index.test_index == nil
+_ = space:create_index("test_index", {parts={1, 'string'}})
+c:reload_schema()
+space.index.test_index ~= nil
+cspace.index.test_index ~= nil
+c.space.test.index.test_index ~= nil
+
+-- cleanup
+
+space:drop()
diff --git a/test/box/net.box_raw_response_gh-3107.result b/test/box/net.box_raw_response_gh-3107.result
new file mode 100644
index 000000000..85fef9daf
--- /dev/null
+++ b/test/box/net.box_raw_response_gh-3107.result
@@ -0,0 +1,123 @@
+fiber = require 'fiber'
+---
+...
+msgpack = require 'msgpack'
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+---
+...
+box.schema.func.create('long_function')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+---
+...
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+---
+...
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+---
+...
+s = box.schema.create_space('test')
+---
+...
+pk = s:create_index('pk')
+---
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{2}
+---
+- [2]
+...
+s:replace{3}
+---
+- [3]
+...
+s:replace{4}
+---
+- [4]
+...
+c = net:connect(box.cfg.listen)
+---
+...
+--
+-- Ensure a request can be finalized from non-caller fibers.
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+---
+...
+ret = {}
+---
+...
+count = 0
+---
+...
+for i = 1, 10 do fiber.create(function() ret[i] = future:wait_result(1000) count = count + 1 end) end
+---
+...
+future:wait_result(0.01) -- Must fail on timeout.
+---
+- null
+- Timeout exceeded
+...
+finalize_long()
+---
+...
+while count ~= 10 do fiber.sleep(0.1) end
+---
+...
+ret
+---
+- - &0 [1, 2, 3]
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+...
+--
+-- Test raw response getting.
+--
+ibuf = require('buffer').ibuf()
+---
+...
+future = c:call('long_function', {1, 2, 3}, {is_async = true, buffer = ibuf})
+---
+...
+finalize_long()
+---
+...
+future:wait_result(100)
+---
+- 10
+...
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+---
+...
+result
+---
+- {48: [1, 2, 3]}
+...
+box.schema.func.drop('long_function')
+---
+...
+c:close()
+---
+...
+s:drop()
+---
+...
diff --git a/test/box/net.box_raw_response_gh-3107.test.lua b/test/box/net.box_raw_response_gh-3107.test.lua
new file mode 100644
index 000000000..fa477d6d7
--- /dev/null
+++ b/test/box/net.box_raw_response_gh-3107.test.lua
@@ -0,0 +1,46 @@
+fiber = require 'fiber'
+msgpack = require 'msgpack'
+net = require('net.box')
+
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+box.schema.func.create('long_function')
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+s = box.schema.create_space('test')
+pk = s:create_index('pk')
+s:replace{1}
+s:replace{2}
+s:replace{3}
+s:replace{4}
+c = net:connect(box.cfg.listen)
+
+--
+-- Ensure a request can be finalized from non-caller fibers.
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+ret = {}
+count = 0
+for i = 1, 10 do fiber.create(function() ret[i] = future:wait_result(1000) count = count + 1 end) end
+future:wait_result(0.01) -- Must fail on timeout.
+finalize_long()
+while count ~= 10 do fiber.sleep(0.1) end
+ret
+
+--
+-- Test raw response getting.
+--
+ibuf = require('buffer').ibuf()
+future = c:call('long_function', {1, 2, 3}, {is_async = true, buffer = ibuf})
+finalize_long()
+future:wait_result(100)
+result, ibuf.rpos = msgpack.decode_unchecked(ibuf.rpos)
+result
+
+box.schema.func.drop('long_function')
+
+c:close()
+s:drop()
diff --git a/test/box/net.box_readahead_gh-3958.result b/test/box/net.box_readahead_gh-3958.result
new file mode 100644
index 000000000..fc2093531
--- /dev/null
+++ b/test/box/net.box_readahead_gh-3958.result
@@ -0,0 +1,55 @@
+test_run = require('test_run').new()
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-3958 updating box.cfg.readahead doesn't affect existing connections.
+--
+readahead = box.cfg.readahead
+---
+...
+box.cfg{readahead = 128}
+---
+...
+s = box.schema.space.create("test")
+---
+...
+_ = s:create_index("pk")
+---
+...
+box.schema.user.grant("guest", "read,write", "space", "test")
+---
+...
+-- connection is created with small readahead value,
+-- make sure it is updated if box.cfg.readahead is changed.
+c = net.connect(box.cfg.listen)
+---
+...
+box.cfg{readahead = 100 * 1024}
+---
+...
+box.error.injection.set("ERRINJ_WAL_DELAY", true)
+---
+- ok
+...
+pad = string.rep('x', 8192)
+---
+...
+for i = 1, 5 do c.space.test:replace({i, pad}, {is_async = true}) end
+---
+...
+box.error.injection.set("ERRINJ_WAL_DELAY", false)
+---
+- ok
+...
+test_run:wait_log('default', 'readahead limit is reached', 1024, 0.1)
+---
+...
+s:drop()
+---
+...
+box.cfg{readahead = readahead}
+---
+...
diff --git a/test/box/net.box_readahead_gh-3958.test.lua b/test/box/net.box_readahead_gh-3958.test.lua
new file mode 100644
index 000000000..1e33a84cb
--- /dev/null
+++ b/test/box/net.box_readahead_gh-3958.test.lua
@@ -0,0 +1,29 @@
+test_run = require('test_run').new()
+net = require('net.box')
+
+--
+-- gh-3958 updating box.cfg.readahead doesn't affect existing connections.
+--
+readahead = box.cfg.readahead
+
+box.cfg{readahead = 128}
+
+s = box.schema.space.create("test")
+_ = s:create_index("pk")
+box.schema.user.grant("guest", "read,write", "space", "test")
+
+-- connection is created with small readahead value,
+-- make sure it is updated if box.cfg.readahead is changed.
+c = net.connect(box.cfg.listen)
+
+box.cfg{readahead = 100 * 1024}
+
+box.error.injection.set("ERRINJ_WAL_DELAY", true)
+pad = string.rep('x', 8192)
+for i = 1, 5 do c.space.test:replace({i, pad}, {is_async = true}) end
+box.error.injection.set("ERRINJ_WAL_DELAY", false)
+
+test_run:wait_log('default', 'readahead limit is reached', 1024, 0.1)
+
+s:drop()
+box.cfg{readahead = readahead}
diff --git a/test/box/net.box_reconnect_after.result b/test/box/net.box_reconnect_after.result
new file mode 100644
index 000000000..a75f9dc5c
--- /dev/null
+++ b/test/box/net.box_reconnect_after.result
@@ -0,0 +1,32 @@
+fiber = require 'fiber'
+---
+...
+net = require('net.box')
+---
+...
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+--
+-- Test a case, when netbox can not connect first time, but
+-- reconnect_after is set.
+--
+c = net.connect('localhost:33333', {reconnect_after = 0.1, wait_connected = false})
+---
+...
+while c.state ~= 'error_reconnect' do fiber.sleep(0.01) end
+---
+...
+c:close()
+---
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
+c.state
+---
+- closed
+...
+c = nil
+---
+...
diff --git a/test/box/net.box_reconnect_after.test.lua b/test/box/net.box_reconnect_after.test.lua
new file mode 100644
index 000000000..8ad870475
--- /dev/null
+++ b/test/box/net.box_reconnect_after.test.lua
@@ -0,0 +1,16 @@
+fiber = require 'fiber'
+net = require('net.box')
+
+box.schema.user.grant('guest', 'execute', 'universe')
+
+--
+-- Test a case, when netbox can not connect first time, but
+-- reconnect_after is set.
+--
+c = net.connect('localhost:33333', {reconnect_after = 0.1, wait_connected = false})
+while c.state ~= 'error_reconnect' do fiber.sleep(0.01) end
+c:close()
+
+box.schema.user.revoke('guest', 'execute', 'universe')
+c.state
+c = nil
diff --git a/test/box/net.box_reconnect_after_gh-3164.result b/test/box/net.box_reconnect_after_gh-3164.result
new file mode 100644
index 000000000..216ce0366
--- /dev/null
+++ b/test/box/net.box_reconnect_after_gh-3164.result
@@ -0,0 +1,119 @@
+fiber = require 'fiber'
+---
+...
+log = require 'log'
+---
+...
+test_run = require('test_run').new()
+---
+...
+net = require('net.box')
+---
+...
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+---
+- true
+...
+--
+-- gh-3164: netbox connection is not closed and garbage collected
+-- ever, if reconnect_after is set.
+--
+test_run:cmd('start server connecter')
+---
+- true
+...
+test_run:cmd("set variable connect_to to 'connecter.listen'")
+---
+- true
+...
+weak = setmetatable({}, {__mode = 'v'})
+---
+...
+-- Create strong and weak reference. Weak is valid until strong
+-- is valid too.
+strong = net.connect(connect_to, {reconnect_after = 0.1})
+---
+...
+weak.c = strong
+---
+...
+weak.c:ping()
+---
+- true
+...
+test_run:cmd('stop server connecter')
+---
+- true
+...
+test_run:cmd('cleanup server connecter')
+---
+- true
+...
+-- Check the connection tries to reconnect at least two times.
+-- 'Cannot assign requested address' is the crutch for running the
+-- tests in a docker. This error emits instead of
+-- 'Connection refused' inside a docker.
+old_log_level = box.cfg.log_level
+---
+...
+box.cfg{log_level = 6}
+---
+...
+log.info(string.rep('a', 1000))
+---
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+while test_run:grep_log('default', 'Network is unreachable', 1000) == nil and
+      test_run:grep_log('default', 'Connection refused', 1000) == nil and
+      test_run:grep_log('default', 'Cannot assign requested address', 1000) == nil do
+       fiber.sleep(0.1)
+end;
+---
+...
+log.info(string.rep('a', 1000));
+---
+...
+while test_run:grep_log('default', 'Network is unreachable', 1000) == nil and
+      test_run:grep_log('default', 'Connection refused', 1000) == nil and
+      test_run:grep_log('default', 'Cannot assign requested address', 1000) == nil do
+       fiber.sleep(0.1)
+end;
+---
+...
+test_run:cmd("setopt delimiter ''");
+---
+- true
+...
+box.cfg{log_level = old_log_level}
+---
+...
+collectgarbage('collect')
+---
+- 0
+...
+strong.state
+---
+- error_reconnect
+...
+strong == weak.c
+---
+- true
+...
+-- Remove single strong reference. Now connection must be garbage
+-- collected.
+strong = nil
+---
+...
+collectgarbage('collect')
+---
+- 0
+...
+-- Now weak.c is null, because it was weak reference, and the
+-- connection is deleted by 'collect'.
+weak.c
+---
+- null
+...
diff --git a/test/box/net.box_reconnect_after_gh-3164.test.lua b/test/box/net.box_reconnect_after_gh-3164.test.lua
new file mode 100644
index 000000000..dc2747080
--- /dev/null
+++ b/test/box/net.box_reconnect_after_gh-3164.test.lua
@@ -0,0 +1,52 @@
+fiber = require 'fiber'
+log = require 'log'
+test_run = require('test_run').new()
+net = require('net.box')
+
+test_run:cmd('create server connecter with script = "box/proxy.lua"')
+
+--
+-- gh-3164: netbox connection is not closed and garbage collected
+-- ever, if reconnect_after is set.
+--
+test_run:cmd('start server connecter')
+test_run:cmd("set variable connect_to to 'connecter.listen'")
+weak = setmetatable({}, {__mode = 'v'})
+-- Create strong and weak reference. Weak is valid until strong
+-- is valid too.
+strong = net.connect(connect_to, {reconnect_after = 0.1})
+weak.c = strong
+weak.c:ping()
+test_run:cmd('stop server connecter')
+test_run:cmd('cleanup server connecter')
+-- Check the connection tries to reconnect at least two times.
+-- 'Cannot assign requested address' is the crutch for running the
+-- tests in a docker. This error emits instead of
+-- 'Connection refused' inside a docker.
+old_log_level = box.cfg.log_level
+box.cfg{log_level = 6}
+log.info(string.rep('a', 1000))
+test_run:cmd("setopt delimiter ';'")
+while test_run:grep_log('default', 'Network is unreachable', 1000) == nil and
+      test_run:grep_log('default', 'Connection refused', 1000) == nil and
+      test_run:grep_log('default', 'Cannot assign requested address', 1000) == nil do
+       fiber.sleep(0.1)
+end;
+log.info(string.rep('a', 1000));
+while test_run:grep_log('default', 'Network is unreachable', 1000) == nil and
+      test_run:grep_log('default', 'Connection refused', 1000) == nil and
+      test_run:grep_log('default', 'Cannot assign requested address', 1000) == nil do
+       fiber.sleep(0.1)
+end;
+test_run:cmd("setopt delimiter ''");
+box.cfg{log_level = old_log_level}
+collectgarbage('collect')
+strong.state
+strong == weak.c
+-- Remove single strong reference. Now connection must be garbage
+-- collected.
+strong = nil
+collectgarbage('collect')
+-- Now weak.c is null, because it was weak reference, and the
+-- connection is deleted by 'collect'.
+weak.c
diff --git a/test/box/net.box_reload_schema_gh-636.result b/test/box/net.box_reload_schema_gh-636.result
new file mode 100644
index 000000000..43e8e8b29
--- /dev/null
+++ b/test/box/net.box_reload_schema_gh-636.result
@@ -0,0 +1,108 @@
+remote = require 'net.box'
+---
+...
+fiber = require 'fiber'
+---
+...
+test_run = require('test_run').new()
+---
+...
+-- #636: Reload schema on demand
+sp = box.schema.space.create('test_old')
+---
+...
+_ = sp:create_index('primary')
+---
+...
+sp:insert{1, 2, 3}
+---
+- [1, 2, 3]
+...
+box.schema.user.grant('guest', 'read', 'space', 'test_old')
+---
+...
+con = remote.new(box.cfg.listen)
+---
+...
+con:ping()
+---
+- true
+...
+con.space.test_old:select{}
+---
+- - [1, 2, 3]
+...
+con.space.test == nil
+---
+- true
+...
+sp = box.schema.space.create('test')
+---
+...
+_ = sp:create_index('primary')
+---
+...
+sp:insert{2, 3, 4}
+---
+- [2, 3, 4]
+...
+box.schema.user.grant('guest', 'read', 'space', 'test')
+---
+...
+con.space.test == nil
+---
+- true
+...
+con:reload_schema()
+---
+...
+con.space.test:select{}
+---
+- - [2, 3, 4]
+...
+box.space.test:drop()
+---
+...
+box.space.test_old:drop()
+---
+...
+con:close()
+---
+...
+name = string.match(arg[0], "([^,]+)%.lua")
+---
+...
+file_log = require('fio').open(name .. '.log', {'O_RDONLY', 'O_NONBLOCK'})
+---
+...
+file_log:seek(0, 'SEEK_END') ~= 0
+---
+- true
+...
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+_ = fiber.create(
+   function()
+         local conn = require('net.box').new(box.cfg.listen)
+         conn:call('no_such_function', {})
+         conn:close()
+   end
+);
+---
+...
+test_run:cmd("setopt delimiter ''");
+---
+- true
+...
+test_run:wait_log('default', 'ER_NO_SUCH_PROC', nil, 10)
+---
+- ER_NO_SUCH_PROC
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
diff --git a/test/box/net.box_reload_schema_gh-636.test.lua b/test/box/net.box_reload_schema_gh-636.test.lua
new file mode 100644
index 000000000..d7431ee6c
--- /dev/null
+++ b/test/box/net.box_reload_schema_gh-636.test.lua
@@ -0,0 +1,46 @@
+remote = require 'net.box'
+fiber = require 'fiber'
+test_run = require('test_run').new()
+
+-- #636: Reload schema on demand
+sp = box.schema.space.create('test_old')
+_ = sp:create_index('primary')
+sp:insert{1, 2, 3}
+
+box.schema.user.grant('guest', 'read', 'space', 'test_old')
+con = remote.new(box.cfg.listen)
+con:ping()
+con.space.test_old:select{}
+con.space.test == nil
+
+sp = box.schema.space.create('test')
+_ = sp:create_index('primary')
+sp:insert{2, 3, 4}
+
+box.schema.user.grant('guest', 'read', 'space', 'test')
+
+con.space.test == nil
+con:reload_schema()
+con.space.test:select{}
+
+box.space.test:drop()
+box.space.test_old:drop()
+con:close()
+
+name = string.match(arg[0], "([^,]+)%.lua")
+file_log = require('fio').open(name .. '.log', {'O_RDONLY', 'O_NONBLOCK'})
+file_log:seek(0, 'SEEK_END') ~= 0
+
+box.schema.user.grant('guest', 'execute', 'universe')
+test_run:cmd("setopt delimiter ';'")
+
+_ = fiber.create(
+   function()
+         local conn = require('net.box').new(box.cfg.listen)
+         conn:call('no_such_function', {})
+         conn:close()
+   end
+);
+test_run:cmd("setopt delimiter ''");
+test_run:wait_log('default', 'ER_NO_SUCH_PROC', nil, 10)
+box.schema.user.revoke('guest', 'execute', 'universe')
diff --git a/test/box/net.box_remote_method_gh-544.result b/test/box/net.box_remote_method_gh-544.result
new file mode 100644
index 000000000..bb92ba998
--- /dev/null
+++ b/test/box/net.box_remote_method_gh-544.result
@@ -0,0 +1,95 @@
+remote = require 'net.box'
+---
+...
+LISTEN = require('uri').parse(box.cfg.listen)
+---
+...
+box.schema.user.create('netbox', { password  = 'test' })
+---
+...
+-- #544 usage for remote[point]method
+cn = remote.connect(LISTEN.host, LISTEN.service)
+---
+...
+box.schema.user.grant('guest', 'execute', 'universe')
+---
+...
+cn:close()
+---
+...
+cn = remote.connect(LISTEN.host, LISTEN.service)
+---
+...
+cn:eval('return true')
+---
+- true
+...
+cn.eval('return true')
+---
+- error: 'Use remote:eval(...) instead of remote.eval(...):'
+...
+cn.ping()
+---
+- error: 'Use remote:ping(...) instead of remote.ping(...):'
+...
+cn:close()
+---
+...
+remote.self:eval('return true')
+---
+- true
+...
+remote.self.eval('return true')
+---
+- error: 'Use remote:eval(...) instead of remote.eval(...):'
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
+-- uri as the first argument
+uri = string.format('%s:%s@%s:%s', 'netbox', 'test', LISTEN.host, LISTEN.service)
+---
+...
+cn = remote.new(uri)
+---
+...
+cn:ping()
+---
+- true
+...
+cn:close()
+---
+...
+uri = string.format('%s@%s:%s', 'netbox', LISTEN.host, LISTEN.service)
+---
+...
+cn = remote.new(uri)
+---
+...
+cn ~= nil, cn.state, cn.error
+---
+- true
+- error
+- Incorrect password supplied for user 'netbox'
+...
+cn:close()
+---
+...
+-- don't merge creds from uri & opts
+remote.new(uri, { password = 'test' })
+---
+- error: 'net.box: user is not defined'
+...
+cn = remote.new(uri, { user = 'netbox', password = 'test' })
+---
+...
+cn:ping()
+---
+- true
+...
+cn:close()
+---
+...
+box.schema.user.drop('netbox')
+---
+...
diff --git a/test/box/net.box_remote_method_gh-544.test.lua b/test/box/net.box_remote_method_gh-544.test.lua
new file mode 100644
index 000000000..cfd883be0
--- /dev/null
+++ b/test/box/net.box_remote_method_gh-544.test.lua
@@ -0,0 +1,40 @@
+remote = require 'net.box'
+
+LISTEN = require('uri').parse(box.cfg.listen)
+box.schema.user.create('netbox', { password  = 'test' })
+
+-- #544 usage for remote[point]method
+cn = remote.connect(LISTEN.host, LISTEN.service)
+
+box.schema.user.grant('guest', 'execute', 'universe')
+cn:close()
+cn = remote.connect(LISTEN.host, LISTEN.service)
+cn:eval('return true')
+cn.eval('return true')
+
+cn.ping()
+
+cn:close()
+
+remote.self:eval('return true')
+remote.self.eval('return true')
+box.schema.user.revoke('guest', 'execute', 'universe')
+
+-- uri as the first argument
+uri = string.format('%s:%s@%s:%s', 'netbox', 'test', LISTEN.host, LISTEN.service)
+
+cn = remote.new(uri)
+cn:ping()
+cn:close()
+
+uri = string.format('%s@%s:%s', 'netbox', LISTEN.host, LISTEN.service)
+cn = remote.new(uri)
+cn ~= nil, cn.state, cn.error
+cn:close()
+-- don't merge creds from uri & opts
+remote.new(uri, { password = 'test' })
+cn = remote.new(uri, { user = 'netbox', password = 'test' })
+cn:ping()
+cn:close()
+
+box.schema.user.drop('netbox')
diff --git a/test/box/net.box_roll_back_gh-822.result b/test/box/net.box_roll_back_gh-822.result
new file mode 100644
index 000000000..5a0550e39
--- /dev/null
+++ b/test/box/net.box_roll_back_gh-822.result
@@ -0,0 +1,68 @@
+remote = require 'net.box'
+---
+...
+test_run = require('test_run').new()
+---
+...
+--
+-- gh-822: net.box.call should roll back local transaction on error
+--
+_ = box.schema.space.create('gh822')
+---
+...
+_ = box.space.gh822:create_index('primary')
+---
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+-- rollback on invalid function
+function rollback_on_invalid_function()
+    box.begin()
+    box.space.gh822:insert{1, "netbox_test"}
+    pcall(remote.self.call, remote.self, 'invalid_function')
+    return box.space.gh822:get(1) == nil
+end;
+---
+...
+rollback_on_invalid_function();
+---
+- true
+...
+-- rollback on call error
+function test_error() error('Some error') end;
+---
+...
+function rollback_on_call_error()
+    box.begin()
+    box.space.gh822:insert{1, "netbox_test"}
+    pcall(remote.self.call, remote.self, 'test_error')
+    return box.space.gh822:get(1) == nil
+end;
+---
+...
+rollback_on_call_error();
+---
+- true
+...
+-- rollback on eval
+function rollback_on_eval_error()
+    box.begin()
+    box.space.gh822:insert{1, "netbox_test"}
+    pcall(remote.self.eval, remote.self, "error('Some error')")
+    return box.space.gh822:get(1) == nil
+end;
+---
+...
+rollback_on_eval_error();
+---
+- true
+...
+test_run:cmd("setopt delimiter ''");
+---
+- true
+...
+box.space.gh822:drop()
+---
+...
diff --git a/test/box/net.box_roll_back_gh-822.test.lua b/test/box/net.box_roll_back_gh-822.test.lua
new file mode 100644
index 000000000..8f4754902
--- /dev/null
+++ b/test/box/net.box_roll_back_gh-822.test.lua
@@ -0,0 +1,42 @@
+remote = require 'net.box'
+test_run = require('test_run').new()
+
+--
+-- gh-822: net.box.call should roll back local transaction on error
+--
+
+_ = box.schema.space.create('gh822')
+_ = box.space.gh822:create_index('primary')
+
+test_run:cmd("setopt delimiter ';'")
+
+-- rollback on invalid function
+function rollback_on_invalid_function()
+    box.begin()
+    box.space.gh822:insert{1, "netbox_test"}
+    pcall(remote.self.call, remote.self, 'invalid_function')
+    return box.space.gh822:get(1) == nil
+end;
+rollback_on_invalid_function();
+
+-- rollback on call error
+function test_error() error('Some error') end;
+function rollback_on_call_error()
+    box.begin()
+    box.space.gh822:insert{1, "netbox_test"}
+    pcall(remote.self.call, remote.self, 'test_error')
+    return box.space.gh822:get(1) == nil
+end;
+rollback_on_call_error();
+
+-- rollback on eval
+function rollback_on_eval_error()
+    box.begin()
+    box.space.gh822:insert{1, "netbox_test"}
+    pcall(remote.self.eval, remote.self, "error('Some error')")
+    return box.space.gh822:get(1) == nil
+end;
+rollback_on_eval_error();
+
+test_run:cmd("setopt delimiter ''");
+box.space.gh822:drop()
diff --git a/test/box/net.box_schema_change_gh-2666.result b/test/box/net.box_schema_change_gh-2666.result
new file mode 100644
index 000000000..bce46bd59
--- /dev/null
+++ b/test/box/net.box_schema_change_gh-2666.result
@@ -0,0 +1,79 @@
+net = require('net.box')
+---
+...
+--
+-- gh-2666: check that netbox.call is not repeated on schema
+-- change.
+--
+box.schema.user.grant('guest', 'write', 'space', '_space')
+---
+...
+box.schema.user.grant('guest', 'write', 'space', '_schema')
+---
+...
+box.schema.user.grant('guest', 'create', 'universe')
+---
+...
+count = 0
+---
+...
+function create_space(name) count = count + 1 box.schema.create_space(name) return true end
+---
+...
+box.schema.func.create('create_space')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'create_space')
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+c:call('create_space', {'test1'})
+---
+- true
+...
+count
+---
+- 1
+...
+c:call('create_space', {'test2'})
+---
+- true
+...
+count
+---
+- 2
+...
+c:call('create_space', {'test3'})
+---
+- true
+...
+count
+---
+- 3
+...
+box.space.test1:drop()
+---
+...
+box.space.test2:drop()
+---
+...
+box.space.test3:drop()
+---
+...
+box.schema.user.revoke('guest', 'write', 'space', '_space')
+---
+...
+box.schema.user.revoke('guest', 'write', 'space', '_schema')
+---
+...
+box.schema.user.revoke('guest', 'create', 'universe')
+---
+...
+c:close()
+---
+...
+box.schema.func.drop('create_space')
+---
+...
diff --git a/test/box/net.box_schema_change_gh-2666.test.lua b/test/box/net.box_schema_change_gh-2666.test.lua
new file mode 100644
index 000000000..16e28e092
--- /dev/null
+++ b/test/box/net.box_schema_change_gh-2666.test.lua
@@ -0,0 +1,28 @@
+net = require('net.box')
+
+--
+-- gh-2666: check that netbox.call is not repeated on schema
+-- change.
+--
+box.schema.user.grant('guest', 'write', 'space', '_space')
+box.schema.user.grant('guest', 'write', 'space', '_schema')
+box.schema.user.grant('guest', 'create', 'universe')
+count = 0
+function create_space(name) count = count + 1 box.schema.create_space(name) return true end
+box.schema.func.create('create_space')
+box.schema.user.grant('guest', 'execute', 'function', 'create_space')
+c = net.connect(box.cfg.listen)
+c:call('create_space', {'test1'})
+count
+c:call('create_space', {'test2'})
+count
+c:call('create_space', {'test3'})
+count
+box.space.test1:drop()
+box.space.test2:drop()
+box.space.test3:drop()
+box.schema.user.revoke('guest', 'write', 'space', '_space')
+box.schema.user.revoke('guest', 'write', 'space', '_schema')
+box.schema.user.revoke('guest', 'create', 'universe')
+c:close()
+box.schema.func.drop('create_space')
diff --git a/test/box/net.box_schema_change_gh-3107.result b/test/box/net.box_schema_change_gh-3107.result
new file mode 100644
index 000000000..233c83307
--- /dev/null
+++ b/test/box/net.box_schema_change_gh-3107.result
@@ -0,0 +1,151 @@
+fiber = require 'fiber'
+---
+...
+net = require('net.box')
+---
+...
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+---
+...
+box.schema.func.create('long_function')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+---
+...
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+---
+...
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+---
+...
+s = box.schema.create_space('test')
+---
+...
+pk = s:create_index('pk')
+---
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{2}
+---
+- [2]
+...
+s:replace{3}
+---
+- [3]
+...
+s:replace{4}
+---
+- [4]
+...
+c = net:connect(box.cfg.listen)
+---
+...
+--
+-- Ensure a request can be finalized from non-caller fibers.
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+---
+...
+ret = {}
+---
+...
+count = 0
+---
+...
+for i = 1, 10 do fiber.create(function() ret[i] = future:wait_result(1000) count = count + 1 end) end
+---
+...
+future:wait_result(0.01) -- Must fail on timeout.
+---
+- null
+- Timeout exceeded
+...
+finalize_long()
+---
+...
+while count ~= 10 do fiber.sleep(0.1) end
+---
+...
+ret
+---
+- - &0 [1, 2, 3]
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+  - *0
+...
+box.schema.func.drop('long_function')
+---
+...
+--
+-- Test async schema version change.
+--
+function change_schema(i) local tmp = box.schema.create_space('test'..i) return 'ok' end
+---
+...
+box.schema.func.create('change_schema')
+---
+...
+box.schema.user.grant('guest', 'execute', 'function', 'change_schema')
+---
+...
+box.schema.user.grant('guest', 'write', 'space', '_schema')
+---
+...
+box.schema.user.grant('guest', 'read,write', 'space', '_space')
+---
+...
+box.schema.user.grant('guest', 'create', 'space')
+---
+...
+future1 = c:call('change_schema', {'1'}, {is_async = true})
+---
+...
+future2 = c:call('change_schema', {'2'}, {is_async = true})
+---
+...
+future3 = c:call('change_schema', {'3'}, {is_async = true})
+---
+...
+future1:wait_result()
+---
+- ['ok']
+...
+future2:wait_result()
+---
+- ['ok']
+...
+future3:wait_result()
+---
+- ['ok']
+...
+c:close()
+---
+...
+s:drop()
+---
+...
+box.schema.func.drop('change_schema')
+---
+...
+box.schema.user.revoke('guest', 'write', 'space', '_schema')
+---
+...
+box.schema.user.revoke('guest', 'read,write', 'space', '_space')
+---
+...
+box.schema.user.revoke('guest', 'create', 'space')
+---
+...
diff --git a/test/box/net.box_schema_change_gh-3107.test.lua b/test/box/net.box_schema_change_gh-3107.test.lua
new file mode 100644
index 000000000..c73788455
--- /dev/null
+++ b/test/box/net.box_schema_change_gh-3107.test.lua
@@ -0,0 +1,55 @@
+fiber = require 'fiber'
+net = require('net.box')
+
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+box.schema.func.create('long_function')
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+s = box.schema.create_space('test')
+pk = s:create_index('pk')
+s:replace{1}
+s:replace{2}
+s:replace{3}
+s:replace{4}
+c = net:connect(box.cfg.listen)
+
+--
+-- Ensure a request can be finalized from non-caller fibers.
+--
+future = c:call('long_function', {1, 2, 3}, {is_async = true})
+ret = {}
+count = 0
+for i = 1, 10 do fiber.create(function() ret[i] = future:wait_result(1000) count = count + 1 end) end
+future:wait_result(0.01) -- Must fail on timeout.
+finalize_long()
+while count ~= 10 do fiber.sleep(0.1) end
+ret
+
+box.schema.func.drop('long_function')
+
+--
+-- Test async schema version change.
+--
+function change_schema(i) local tmp = box.schema.create_space('test'..i) return 'ok' end
+box.schema.func.create('change_schema')
+box.schema.user.grant('guest', 'execute', 'function', 'change_schema')
+box.schema.user.grant('guest', 'write', 'space', '_schema')
+box.schema.user.grant('guest', 'read,write', 'space', '_space')
+box.schema.user.grant('guest', 'create', 'space')
+future1 = c:call('change_schema', {'1'}, {is_async = true})
+future2 = c:call('change_schema', {'2'}, {is_async = true})
+future3 = c:call('change_schema', {'3'}, {is_async = true})
+future1:wait_result()
+future2:wait_result()
+future3:wait_result()
+
+c:close()
+s:drop()
+box.schema.func.drop('change_schema')
+box.schema.user.revoke('guest', 'write', 'space', '_schema')
+box.schema.user.revoke('guest', 'read,write', 'space', '_space')
+box.schema.user.revoke('guest', 'create', 'space')
diff --git a/test/box/net.box_session_type_gh-2642.result b/test/box/net.box_session_type_gh-2642.result
new file mode 100644
index 000000000..0e043f6e5
--- /dev/null
+++ b/test/box/net.box_session_type_gh-2642.result
@@ -0,0 +1,22 @@
+net = require('net.box')
+---
+...
+--
+-- gh-2642: box.session.type()
+--
+box.schema.user.grant('guest','execute','universe')
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+c:call("box.session.type")
+---
+- binary
+...
+c:close()
+---
+...
+box.schema.user.revoke('guest', 'execute', 'universe')
+---
+...
diff --git a/test/box/net.box_session_type_gh-2642.test.lua b/test/box/net.box_session_type_gh-2642.test.lua
new file mode 100644
index 000000000..4e3cf5265
--- /dev/null
+++ b/test/box/net.box_session_type_gh-2642.test.lua
@@ -0,0 +1,11 @@
+net = require('net.box')
+
+--
+-- gh-2642: box.session.type()
+--
+
+box.schema.user.grant('guest','execute','universe')
+c = net.connect(box.cfg.listen)
+c:call("box.session.type")
+c:close()
+box.schema.user.revoke('guest', 'execute', 'universe')
diff --git a/test/box/net.box_space_format_gh-2402.result b/test/box/net.box_space_format_gh-2402.result
new file mode 100644
index 000000000..c66665c73
--- /dev/null
+++ b/test/box/net.box_space_format_gh-2402.result
@@ -0,0 +1,49 @@
+net = require('net.box')
+---
+...
+--
+-- gh-2402 net.box doesn't support space:format()
+--
+space = box.schema.space.create('test', {format={{name="id", type="unsigned"}}})
+---
+...
+space ~= nil
+---
+- true
+...
+_ = box.space.test:create_index('primary')
+---
+...
+box.schema.user.grant('guest', 'read', 'space', 'test')
+---
+...
+c = net.connect(box.cfg.listen)
+---
+...
+c:ping()
+---
+- true
+...
+c.space.test ~= nil
+---
+- true
+...
+format = c.space.test:format()
+---
+...
+format[1] ~= nil
+---
+- true
+...
+format[1].name == "id"
+---
+- true
+...
+format[1].type == "unsigned"
+---
+- true
+...
+c.space.test:format({})
+---
+- error: net.box does not support setting space format
+...
diff --git a/test/box/net.box_space_format_gh-2402.test.lua b/test/box/net.box_space_format_gh-2402.test.lua
new file mode 100644
index 000000000..020f20da6
--- /dev/null
+++ b/test/box/net.box_space_format_gh-2402.test.lua
@@ -0,0 +1,23 @@
+net = require('net.box')
+
+--
+-- gh-2402 net.box doesn't support space:format()
+--
+
+space = box.schema.space.create('test', {format={{name="id", type="unsigned"}}})
+space ~= nil
+_ = box.space.test:create_index('primary')
+box.schema.user.grant('guest', 'read', 'space', 'test')
+
+c = net.connect(box.cfg.listen)
+
+c:ping()
+c.space.test ~= nil
+
+format = c.space.test:format()
+
+format[1] ~= nil
+format[1].name == "id"
+format[1].type == "unsigned"
+
+c.space.test:format({})
diff --git a/test/box/net.box_timeout-gh-3107.result b/test/box/net.box_timeout-gh-3107.result
new file mode 100644
index 000000000..be7f9606c
--- /dev/null
+++ b/test/box/net.box_timeout-gh-3107.result
@@ -0,0 +1,125 @@
+-- test-run result file version 2
+fiber = require 'fiber'
+ | ---
+ | ...
+net = require('net.box')
+ | ---
+ | ...
+
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+ | ---
+ | ...
+box.schema.func.create('long_function')
+ | ---
+ | ...
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+ | ---
+ | ...
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+ | ---
+ | ...
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+ | ---
+ | ...
+s = box.schema.create_space('test')
+ | ---
+ | ...
+pk = s:create_index('pk')
+ | ---
+ | ...
+s:replace{1}
+ | ---
+ | - [1]
+ | ...
+s:replace{2}
+ | ---
+ | - [2]
+ | ...
+s:replace{3}
+ | ---
+ | - [3]
+ | ...
+s:replace{4}
+ | ---
+ | - [4]
+ | ...
+c = net:connect(box.cfg.listen)
+ | ---
+ | ...
+
+--
+-- Check infinity timeout.
+--
+ret = nil
+ | ---
+ | ...
+_ = fiber.create(function() ret = c:call('long_function', {1, 2, 3}, {is_async = true}):wait_result() end)
+ | ---
+ | ...
+finalize_long()
+ | ---
+ | ...
+while not ret do fiber.sleep(0.01) end
+ | ---
+ | ...
+ret
+ | ---
+ | - [1, 2, 3]
+ | ...
+c:close()
+ | ---
+ | ...
+box.schema.user.grant('guest', 'execute', 'universe')
+ | ---
+ | ...
+c = net:connect(box.cfg.listen)
+ | ---
+ | ...
+future = c:eval('return long_function(...)', {1, 2, 3}, {is_async = true})
+ | ---
+ | ...
+future:result()
+ | ---
+ | - null
+ | - Response is not ready
+ | ...
+future:wait_result(0.01) -- Must fail on timeout.
+ | ---
+ | - null
+ | - Timeout exceeded
+ | ...
+finalize_long()
+ | ---
+ | ...
+future:wait_result(100)
+ | ---
+ | - [1, 2, 3]
+ | ...
+
+c:close()
+ | ---
+ | ...
+--
+-- Check that is_async does not work on a closed connection.
+--
+c:call('any_func', {}, {is_async = true})
+ | ---
+ | - error: Connection closed
+ | ...
+
+box.schema.user.revoke('guest', 'execute', 'universe')
+ | ---
+ | ...
+c = net:connect(box.cfg.listen)
+ | ---
+ | ...
+
+c:close()
+ | ---
+ | ...
+s:drop()
+ | ---
+ | ...
diff --git a/test/box/net.box_timeout-gh-3107.test.lua b/test/box/net.box_timeout-gh-3107.test.lua
new file mode 100644
index 000000000..08fa039db
--- /dev/null
+++ b/test/box/net.box_timeout-gh-3107.test.lua
@@ -0,0 +1,47 @@
+fiber = require 'fiber'
+net = require('net.box')
+
+--
+-- gh-3107: fiber-async netbox.
+--
+cond = nil
+box.schema.func.create('long_function')
+box.schema.user.grant('guest', 'execute', 'function', 'long_function')
+function long_function(...) cond = fiber.cond() cond:wait() return ... end
+function finalize_long() while not cond do fiber.sleep(0.01) end cond:signal() cond = nil end
+s = box.schema.create_space('test')
+pk = s:create_index('pk')
+s:replace{1}
+s:replace{2}
+s:replace{3}
+s:replace{4}
+c = net:connect(box.cfg.listen)
+
+--
+-- Check infinity timeout.
+--
+ret = nil
+_ = fiber.create(function() ret = c:call('long_function', {1, 2, 3}, {is_async = true}):wait_result() end)
+finalize_long()
+while not ret do fiber.sleep(0.01) end
+ret
+c:close()
+box.schema.user.grant('guest', 'execute', 'universe')
+c = net:connect(box.cfg.listen)
+future = c:eval('return long_function(...)', {1, 2, 3}, {is_async = true})
+future:result()
+future:wait_result(0.01) -- Must fail on timeout.
+finalize_long()
+future:wait_result(100)
+
+c:close()
+--
+-- Check that is_async does not work on a closed connection.
+--
+c:call('any_func', {}, {is_async = true})
+
+box.schema.user.revoke('guest', 'execute', 'universe')
+c = net:connect(box.cfg.listen)
+
+c:close()
+s:drop()
diff --git a/test/box/net.box_timeout_gh-1533.result b/test/box/net.box_timeout_gh-1533.result
new file mode 100644
index 000000000..10dccd74f
--- /dev/null
+++ b/test/box/net.box_timeout_gh-1533.result
@@ -0,0 +1,89 @@
+fiber = require 'fiber'
+---
+...
+test_run = require('test_run').new()
+---
+...
+net = require('net.box')
+---
+...
+-- Tarantool < 1.7.1 compatibility (gh-1533)
+c = net.new(box.cfg.listen)
+---
+...
+c:ping()
+---
+- true
+...
+c:close()
+---
+...
+-- Test for connect_timeout > 0 in netbox connect
+test_run:cmd("setopt delimiter ';'");
+---
+- true
+...
+need_stop = false;
+---
+...
+greeting =
+"Tarantool 1.7.3 (Lua console)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" ..
+"type 'help' for interactive help~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
+---
+...
+socket = require('socket');
+---
+...
+srv = socket.tcp_server('localhost', 0, {
+    handler = function(fd)
+        local fiber = require('fiber')
+        while not need_stop do
+            fiber.sleep(0.01)
+        end
+        fd:write(greeting)
+    end
+});
+---
+...
+-- we must get timeout
+port = srv:name().port
+nb = net.new('localhost:' .. port, {
+    wait_connected = true, console = true,
+    connect_timeout = 0.1
+});
+---
+...
+nb.error:find('timed out') ~= nil;
+---
+- true
+...
+need_stop = true
+nb:close();
+---
+...
+-- we must get peer closed
+nb = net.new('localhost:' .. port, {
+    wait_connected = true, console = true,
+    connect_timeout = 0.2
+});
+---
+...
+nb.error ~= "Timeout exceeded";
+---
+- true
+...
+nb:close();
+---
+...
+test_run:cmd("setopt delimiter ''");
+---
+- true
+...
+srv:close()
+---
+- true
+...
+test_run:cmd("clear filter")
+---
+- true
+...
diff --git a/test/box/net.box_timeout_gh-1533.test.lua b/test/box/net.box_timeout_gh-1533.test.lua
new file mode 100644
index 000000000..08fddb0bb
--- /dev/null
+++ b/test/box/net.box_timeout_gh-1533.test.lua
@@ -0,0 +1,45 @@
+fiber = require 'fiber'
+test_run = require('test_run').new()
+net = require('net.box')
+
+-- Tarantool < 1.7.1 compatibility (gh-1533)
+c = net.new(box.cfg.listen)
+c:ping()
+c:close()
+
+-- Test for connect_timeout > 0 in netbox connect
+test_run:cmd("setopt delimiter ';'");
+need_stop = false;
+greeting =
+"Tarantool 1.7.3 (Lua console)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" ..
+"type 'help' for interactive help~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
+socket = require('socket');
+srv = socket.tcp_server('localhost', 0, {
+    handler = function(fd)
+        local fiber = require('fiber')
+        while not need_stop do
+            fiber.sleep(0.01)
+        end
+        fd:write(greeting)
+    end
+});
+port = srv:name().port
+-- we must get timeout
+nb = net.new('localhost:' .. port, {
+    wait_connected = true, console = true,
+    connect_timeout = 0.1
+});
+nb.error:find('timed out') ~= nil;
+need_stop = true
+nb:close();
+-- we must get peer closed
+nb = net.new('localhost:' .. port, {
+    wait_connected = true, console = true,
+    connect_timeout = 0.2
+});
+nb.error ~= "Timeout exceeded";
+nb:close();
+test_run:cmd("setopt delimiter ''");
+srv:close()
+
+test_run:cmd("clear filter")
diff --git a/test/box/net.box_upsert_gh-970.result b/test/box/net.box_upsert_gh-970.result
new file mode 100644
index 000000000..d3ec20c23
--- /dev/null
+++ b/test/box/net.box_upsert_gh-970.result
@@ -0,0 +1,49 @@
+net = require('net.box')
+---
+...
+-- gh-970 gh-971 UPSERT over network
+_ = box.schema.space.create('test')
+---
+...
+_ = box.space.test:create_index('primary', {type = 'TREE', parts = {1,'unsigned'}})
+---
+...
+_ = box.space.test:create_index('covering', {type = 'TREE', parts = {1,'unsigned',3,'string',2,'unsigned'}})
+---
+...
+_ = box.space.test:insert{1, 2, "string"}
+---
+...
+box.schema.user.grant('guest', 'read,write', 'space', 'test')
+---
+...
+c = net:connect(box.cfg.listen)
+---
+...
+c.space.test:select{}
+---
+- - [1, 2, 'string']
+...
+c.space.test:upsert({1, 2, 'nothing'}, {{'+', 2, 1}}) -- common update
+---
+...
+c.space.test:select{}
+---
+- - [1, 3, 'string']
+...
+c.space.test:upsert({2, 4, 'something'}, {{'+', 2, 1}}) -- insert
+---
+...
+c.space.test:select{}
+---
+- - [1, 3, 'string']
+  - [2, 4, 'something']
+...
+c.space.test:upsert({2, 4, 'nothing'}, {{'+', 3, 100500}}) -- wrong operation
+---
+...
+c.space.test:select{}
+---
+- - [1, 3, 'string']
+  - [2, 4, 'something']
+...
diff --git a/test/box/net.box_upsert_gh-970.test.lua b/test/box/net.box_upsert_gh-970.test.lua
new file mode 100644
index 000000000..0ea9092eb
--- /dev/null
+++ b/test/box/net.box_upsert_gh-970.test.lua
@@ -0,0 +1,16 @@
+net = require('net.box')
+
+-- gh-970 gh-971 UPSERT over network
+_ = box.schema.space.create('test')
+_ = box.space.test:create_index('primary', {type = 'TREE', parts = {1,'unsigned'}})
+_ = box.space.test:create_index('covering', {type = 'TREE', parts = {1,'unsigned',3,'string',2,'unsigned'}})
+_ = box.space.test:insert{1, 2, "string"}
+box.schema.user.grant('guest', 'read,write', 'space', 'test')
+c = net:connect(box.cfg.listen)
+c.space.test:select{}
+c.space.test:upsert({1, 2, 'nothing'}, {{'+', 2, 1}}) -- common update
+c.space.test:select{}
+c.space.test:upsert({2, 4, 'something'}, {{'+', 2, 1}}) -- insert
+c.space.test:select{}
+c.space.test:upsert({2, 4, 'nothing'}, {{'+', 3, 100500}}) -- wrong operation
+c.space.test:select{}
diff --git a/test/box/net.box_wait_connected_gh-3856.result b/test/box/net.box_wait_connected_gh-3856.result
new file mode 100644
index 000000000..9234e6cb9
--- /dev/null
+++ b/test/box/net.box_wait_connected_gh-3856.result
@@ -0,0 +1,20 @@
+net = require('net.box')
+---
+...
+--
+-- gh-3856: wait_connected = false is ignored.
+--
+c = net.connect('8.8.8.8:123456', {wait_connected = false})
+---
+...
+c
+---
+- opts:
+    wait_connected: false
+  host: 8.8.8.8
+  state: initial
+  port: '123456'
+...
+c:close()
+---
+...
diff --git a/test/box/net.box_wait_connected_gh-3856.test.lua b/test/box/net.box_wait_connected_gh-3856.test.lua
new file mode 100644
index 000000000..29e997fb5
--- /dev/null
+++ b/test/box/net.box_wait_connected_gh-3856.test.lua
@@ -0,0 +1,8 @@
+net = require('net.box')
+
+--
+-- gh-3856: wait_connected = false is ignored.
+--
+c = net.connect('8.8.8.8:123456', {wait_connected = false})
+c
+c:close()
-- 
2.17.1



More information about the Tarantool-patches mailing list