commit - 2515ab166e77192a440be01082aa3a28ce75dc42
commit + 98c91930fd736b4ae9a48fd88e4ceee4db258d20
blob - e4fc51c2d8235be128ccb8fc3715e7c747ee2986
blob + 5de28463f41054a99af2791b61ae57ddb876ca08
--- src/box/box.cc
+++ src/box/box.cc
void
box_init(void)
{
+ iproto_constants_init();
box_on_recovery_state_event =
event_get("box.ctl.on_recovery_state", true);
event_ref(box_on_recovery_state_event);
box_on_recovery_state_event = NULL;
txn_event_trigger_free();
tuple_free();
+ iproto_constants_free();
/* schema_module_free(); */
/* session_free(); */
/* user_cache_free(); */
blob - 0a70681c8c361ca673992987f1762d89faae72eb
blob + 8514e85a013e5a29e608bdad6dc2ac7de3d40c8a
--- src/box/iproto.cc
+++ src/box/iproto.cc
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>
+#include <ctype.h>
#include <msgpuck.h>
#include <small/ibuf.h>
#include "version.h"
#include "event.h"
+#include "func_adapter.h"
#include "fiber.h"
#include "fiber_cond.h"
#include "cbus.h"
/**
* Request handlers meta information. The IPROTO request of each type can be
* overridden by the following types of handlers (listed in priority order):
- * 1. C handler, set by `iproto_override()'.
+ * 1. Lua handlers, set in the event registry by request type id;
+ * 2. Lua handlers, set in the event registry by request type name;
+ * 3. C handler, set by `iproto_override()'.
*/
struct iproto_req_handlers {
/**
+ * Triggers from the event registry, set by request type id.
+ * NULL if no such triggers.
+ */
+ struct event *event_by_id;
+ /**
+ * Triggers from the event registry, set by request type name.
+ * NULL if no such triggers.
+ */
+ struct event *event_by_name;
+ /**
* C request handler.
*/
struct {
static void
iproto_req_handlers_delete(struct iproto_req_handlers *handlers)
{
+ if (handlers->event_by_id != NULL)
+ event_unref(handlers->event_by_id);
+ if (handlers->event_by_name != NULL)
+ event_unref(handlers->event_by_name);
if (handlers->c.destroy != NULL)
handlers->c.destroy(handlers->c.ctx);
TRASH(handlers);
}
/**
+ * Replaces an event in `handlers' by the new `event'. If `is_by_id', the
+ * handler is set by request type id, otherwise it is set by request type name.
+ */
+static void
+iproto_req_handlers_set_event(struct iproto_req_handlers *handlers,
+ struct event *event, bool is_by_id)
+{
+ assert(handlers != NULL);
+ assert(event != NULL);
+
+ if (is_by_id) {
+ if (handlers->event_by_id == NULL) {
+ event_ref(event);
+ handlers->event_by_id = event;
+ } else {
+ assert(handlers->event_by_id == event);
+ }
+ } else {
+ if (handlers->event_by_name == NULL) {
+ event_ref(event);
+ handlers->event_by_name = event;
+ } else {
+ assert(handlers->event_by_name == event);
+ }
+ }
+}
+
+/**
* Returns `true' if there is at least one handler in `handlers'.
*/
static bool
if (handlers == NULL)
return false;
- return handlers->c.cb != NULL;
+ return handlers->event_by_id != NULL ||
+ handlers->event_by_name != NULL ||
+ handlers->c.cb != NULL;
+}
+
+/**
+ * Returns `enum iproto_type' if `name' is a valid IPROTO type name or equals
+ * "unknown". Otherwise, iproto_type_MAX is returned. The name is expected to
+ * be in lowercase.
+ */
+static enum iproto_type
+get_iproto_type_by_name(const char *name)
+{
+ for (uint32_t i = 0; i < iproto_type_MAX; i++) {
+ const char *type_name = iproto_type_name_lower(i);
+ if (type_name != NULL && strcmp(type_name, name) == 0)
+ return (enum iproto_type)i;
+ }
+ if (strcmp(name, "unknown") == 0)
+ return IPROTO_UNKNOWN;
+ return iproto_type_MAX;
+}
+
+/**
+ * Runs triggers registered for the `event'.
+ * The given header and body the IPROTO packet are passed as trigger args.
+ * Returns IPROTO_HANDLER_OK if some trigger successfully handled the request,
+ * IPROTO_HANDLER_FALLBACK if no triggers handled the request, or
+ * IPROTO_HANDLER_ERROR on failure.
+ */
+static enum iproto_handler_status
+tx_run_override_triggers(struct event *event, const char *header,
+ const char *header_end, const char *body,
+ const char *body_end)
+{
+ enum iproto_handler_status rc = IPROTO_HANDLER_FALLBACK;
+ const char *name = NULL;
+ struct func_adapter *trigger = NULL;
+ struct func_adapter_ctx ctx;
+ struct event_trigger_iterator it;
+ event_trigger_iterator_create(&it, event);
+
+ while (event_trigger_iterator_next(&it, &trigger, &name)) {
+ struct mp_ctx mp_ctx_header, mp_ctx_body;
+ mp_ctx_create_default(&mp_ctx_header, iproto_key_translation);
+ mp_ctx_create_default(&mp_ctx_body, iproto_key_translation);
+
+ func_adapter_begin(trigger, &ctx);
+ func_adapter_push_msgpack_with_ctx(trigger, &ctx, header,
+ header_end, &mp_ctx_header);
+ func_adapter_push_msgpack_with_ctx(trigger, &ctx, body,
+ body_end, &mp_ctx_body);
+ if (func_adapter_call(trigger, &ctx) == 0) {
+ if (func_adapter_is_bool(trigger, &ctx)) {
+ bool ok = false;
+ func_adapter_pop_bool(trigger, &ctx, &ok);
+ if (ok)
+ rc = IPROTO_HANDLER_OK;
+ } else {
+ diag_set(ClientError, ER_PROC_LUA,
+ "Invalid Lua IPROTO handler return "
+ "type: expected boolean");
+ rc = IPROTO_HANDLER_ERROR;
+ }
+ } else {
+ rc = IPROTO_HANDLER_ERROR;
+ }
+ func_adapter_end(trigger, &ctx);
+ if (rc != IPROTO_HANDLER_FALLBACK)
+ break;
+ }
+ event_trigger_iterator_destroy(&it);
+ return rc;
}
/**
if (handlers == NULL)
handlers = mh_req_handlers_get(IPROTO_UNKNOWN);
assert(handlers != NULL);
- enum iproto_handler_status rc;
+ enum iproto_handler_status rc = IPROTO_HANDLER_FALLBACK;
- rc = handlers->c.cb(header, header_end, body, body_end,
- handlers->c.ctx);
+ /*
+ * Run handlers from the event registry, set by request type id.
+ */
+ if (handlers->event_by_id != NULL) {
+ rc = tx_run_override_triggers(handlers->event_by_id, header,
+ header_end, body, body_end);
+ }
+ /*
+ * Run handlers from the event registry, set by request type name.
+ */
+ if (rc == IPROTO_HANDLER_FALLBACK && handlers->event_by_name != NULL) {
+ rc = tx_run_override_triggers(handlers->event_by_name, header,
+ header_end, body, body_end);
+ }
+ /*
+ * Run C handlers.
+ */
+ if (rc == IPROTO_HANDLER_FALLBACK && handlers->c.cb != NULL) {
+ rc = handlers->c.cb(header, header_end, body, body_end,
+ handlers->c.ctx);
+ }
struct cmsg_hop *route = NULL;
switch (rc) {
iproto_thread->tx.requests_in_progress = 0;
iproto_thread->requests_in_stream_queue = 0;
rlist_create(&iproto_thread->connections);
+}
+
+/**
+ * True for IPROTO request types that can be overridden.
+ */
+static bool
+is_iproto_override_supported(uint32_t req_type)
+{
+ switch (req_type) {
+ case IPROTO_JOIN:
+ case IPROTO_SUBSCRIBE:
+ case IPROTO_FETCH_SNAPSHOT:
+ case IPROTO_REGISTER:
+ return false;
+ default:
+ return true;
+ }
}
+/**
+ * If the `name' contains a valid name of an IPROTO overriding event, sets
+ * `req_type' and returns True. If the name contains correct prefix, but
+ * the request type is invalid, the error is logged with CRIT log level.
+ * `is_by_id' set to True if the request is overridden by id, False if by name.
+ */
+static bool
+get_iproto_type_from_event_name(const char *name, uint32_t *req_type,
+ bool *is_by_id)
+{
+ const char *prefix = "box.iproto.override";
+ const size_t prefix_len = strlen(prefix);
+ if (strncmp(name, prefix, prefix_len) != 0)
+ return false;
+
+ const char *req_name = name + prefix_len;
+ const char *req_name_err = req_name;
+ if (*req_name == '.') {
+ *is_by_id = false;
+ /* Skip the dot. */
+ req_name++;
+ req_name_err = req_name;
+ *req_type = get_iproto_type_by_name(req_name);
+ if (*req_type == iproto_type_MAX)
+ goto err_bad_type;
+ } else if (*req_name == '[') {
+ *is_by_id = true;
+ /* Skip open bracket. */
+ req_name++;
+ if (!isdigit(*req_name) && *req_name != '-')
+ goto err_bad_type;
+ char *endptr;
+ *req_type = strtol(req_name, &endptr, 10);
+ if (endptr == req_name)
+ goto err_bad_type;
+ /*
+ * At least one digit is parsed.
+ * Check that the rest of the string equals "]".
+ */
+ if (*endptr != ']' || endptr[1] != 0)
+ goto err_bad_type;
+ } else {
+ /* Not in IPROTO override namespace. */
+ return false;
+ }
+
+ if (!is_iproto_override_supported(*req_type)) {
+ say_crit("IPROTO request handler overriding does not support "
+ "`%s' request type", iproto_type_name(*req_type));
+ return false;
+ }
+ return true;
+
+err_bad_type:
+ say_crit("The event `%s' is in IPROTO override namespace, but `%s' is "
+ "not a valid request type", name, req_name_err);
+ return false;
+}
+
+/**
+ * Gets an arbitrary `event', checks its name, and adds it to `req_handlers' if
+ * it is a valid IPROTO overriding event.
+ * If the event name contains correct IPROTO overriding prefix, but the request
+ * type is invalid, the error is logged with CRIT log level.
+ */
+static bool
+iproto_override_event_init(struct event *event, void *arg)
+{
+ (void)arg;
+ uint32_t type;
+ bool is_by_id;
+ if (!get_iproto_type_from_event_name(event->name, &type, &is_by_id))
+ return true;
+
+ struct iproto_req_handlers *handlers = mh_req_handlers_get(type);
+ if (handlers == NULL) {
+ handlers = iproto_req_handlers_new();
+ mh_req_handlers_put(type, handlers);
+ }
+ iproto_req_handlers_set_event(handlers, event, is_by_id);
+
+ for (int i = 0; i < iproto_threads_count; i++) {
+ struct iproto_thread *iproto_thread = &iproto_threads[i];
+ mh_i32_put(iproto_thread->req_handlers, &type, NULL, NULL);
+ }
+ return true;
+}
+
+/**
+ * Notifies IPROTO threads that a new request handler has been set.
+ */
+static void
+iproto_cfg_override(uint32_t req_type, bool is_set);
+
+/**
+ * Calls iproto_cfg_override() and destroys the handlers when necessary.
+ */
+static void
+iproto_override_finish(struct iproto_req_handlers *handlers, uint32_t req_type,
+ bool old_is_set)
+{
+ bool new_is_set = iproto_req_handler_is_set(handlers);
+ if (new_is_set != old_is_set)
+ iproto_cfg_override(req_type, new_is_set);
+
+ if (!new_is_set && handlers != NULL) {
+ mh_req_handlers_del(req_type);
+ iproto_req_handlers_delete(handlers);
+ }
+}
+
/** Initialize the iproto subsystem and start network io thread */
void
iproto_init(int threads_count)
struct iproto_thread *iproto_thread = &iproto_threads[i];
iproto_thread->id = i;
iproto_thread_init(iproto_thread);
+ }
+
+ /*
+ * Go through all events with triggers, and initialize overridden
+ * request handlers that were registered before IPROTO initialization.
+ */
+ tx_req_handlers = mh_i32ptr_new();
+ event_foreach(iproto_override_event_init, NULL);
+
+ for (int i = 0; i < threads_count; i++) {
+ struct iproto_thread *iproto_thread = &iproto_threads[i];
if (cord_costart(&iproto_thread->net_cord, "iproto",
net_cord_f, iproto_thread))
panic("failed to start iproto thread");
iproto_msg_max / 2);
}
- tx_req_handlers = mh_i32ptr_new();
session_vtab_registry[SESSION_TYPE_BINARY] = iproto_session_vtab;
if (box_on_shutdown(NULL, iproto_on_shutdown_f, NULL) != 0)
return 0;
}
-/**
- * Notifies IPROTO threads that a new request handler has been set.
- */
static void
iproto_cfg_override(uint32_t req_type, bool is_set)
{
iproto_override(uint32_t req_type, iproto_handler_t cb,
iproto_handler_destroy_t destroy, void *ctx)
{
- if (req_type == IPROTO_JOIN || req_type == IPROTO_FETCH_SNAPSHOT ||
- req_type == IPROTO_REGISTER || req_type == IPROTO_SUBSCRIBE) {
+ if (!is_iproto_override_supported(req_type)) {
const char *feature = tt_sprintf("%s request type",
iproto_type_name(req_type));
diag_set(ClientError, ER_UNSUPPORTED,
struct iproto_req_handlers *handlers;
handlers = mh_req_handlers_get(req_type);
- bool old_is_set = iproto_req_handler_is_set(handlers);
+ bool is_set = iproto_req_handler_is_set(handlers);
if (handlers != NULL && handlers->c.destroy != NULL)
handlers->c.destroy(handlers->c.ctx);
handlers->c.ctx = NULL;
}
- bool new_is_set = iproto_req_handler_is_set(handlers);
- if (new_is_set != old_is_set)
- iproto_cfg_override(req_type, new_is_set);
-
- if (!new_is_set && handlers != NULL) {
- mh_req_handlers_del(req_type);
- iproto_req_handlers_delete(handlers);
- }
+ iproto_override_finish(handlers, req_type, is_set);
return 0;
}
blob - 9040f7bf550a099ad064362f806c8f934777200f
blob + 64344213647cdb61d14e77c5c0e22bc02916b3fc
--- src/box/iproto_constants.c
+++ src/box/iproto_constants.c
IPROTO_TYPES(IPROTO_TYPE_STRS_MEMBER)
};
+char *iproto_type_lower_strs[iproto_type_MAX];
+
#define IPROTO_RAFT_KEY_STRS_MEMBER(s, ...) \
[IPROTO_RAFT_ ## s] = #s,
blob - fa00b5b60b4d1729652f2e5604e3d9279e1eb392
blob + df6795650d5c48e2df9135a56c5b23a17409d1f9
--- src/box/iproto_constants.h
+++ src/box/iproto_constants.h
/** IPROTO type name by code */
extern const char *iproto_type_strs[];
+
+/** IPROTO type name by code, in lower case. */
+extern char *iproto_type_lower_strs[];
#define IPROTO_RAFT_KEYS(_) \
_(TERM, 0) \
default:
return NULL;
}
+}
+
+/** Returns lowercase IPROTO type name by IPROTO `type'. */
+static inline const char *
+iproto_type_name_lower(uint16_t type)
+{
+ if (type < iproto_type_MAX)
+ return iproto_type_lower_strs[type];
+ return NULL;
}
/** Predefined replication group identifiers. */
return vy_row_index_key_strs[key];
}
+/** Initialize the "IPROTO constants" subsystem. */
+static inline void
+iproto_constants_init(void)
+{
+ for (size_t i = 0; i < iproto_type_MAX; i++) {
+ const char *type_name = iproto_type_strs[i];
+ iproto_type_lower_strs[i] = type_name == NULL ? NULL :
+ strtolowerdup(type_name);
+ }
+}
+
+/** Destroy the "IPROTO constants" subsystem. */
+static inline void
+iproto_constants_free(void)
+{
+ for (size_t i = 0; i < iproto_type_MAX; i++) {
+ free(iproto_type_lower_strs[i]);
+ iproto_type_lower_strs[i] = NULL;
+ }
+}
+
#if defined(__cplusplus)
} /* extern "C" */
#endif
blob - 41f064857dd885e4daa5898871bbd703f7c9a20b
blob + 053ef6d83a1310aa508b7546dcc9ee221ef16e93
--- test/box-luatest/iproto_request_handlers_overriding_test.lua
+++ test/box-luatest/iproto_request_handlers_overriding_test.lua
local server = require('luatest.server')
local t = require('luatest')
+-- Keep in sync with `is_iproto_override_supported' in `iproto.cc'.
+local unsupported_rq_types = {
+ JOIN = box.iproto.type.JOIN,
+ SUBSCRIBE = box.iproto.type.SUBSCRIBE,
+ FETCH_SNAPSHOT = box.iproto.type.FETCH_SNAPSHOT,
+ REGISTER = box.iproto.type.REGISTER,
+}
+
+-- Grep server logs for error messages about unsupported request types.
+local function check_unsupported_rq_types(cg)
+ local msg
+ for req in pairs(unsupported_rq_types) do
+ msg = "C> IPROTO request handler overriding does not support `" ..
+ req .. "' request type"
+ t.assert(cg.server:grep_log(msg))
+ end
+end
+
local g = t.group()
g.before_all(function(cg)
-- Checks that `box.iproto.override` errors are handled correctly.
g.test_box_iproto_override_errors = function(cg)
- cg.server:exec(function()
+ cg.server:exec(function(unsupported_rq_types)
local err_msg = "Usage: box.iproto.override(request_type, callback)"
t.assert_error_msg_content_equals(err_msg, function()
box.iproto.override()
t.assert_error_msg_content_equals(err_msg, function()
box.iproto.override(0, 'str')
end)
- local unsupported_rq_types = {
- JOIN = box.iproto.type.JOIN,
- FETCH_SNAPSHOT = box.iproto.type.FETCH_SNAPSHOT,
- REGISTER = box.iproto.type.REGISTER,
- SUBSCRIBE = box.iproto.type.SUBSCRIBE,
- }
for rq_name, rq_type in pairs(unsupported_rq_types) do
err_msg = ("IPROTO request handler overriding does not " ..
"support %s request type"):format(rq_name)
box.iproto.override(rq_type, function() end)
end)
end
- end)
+ end, {unsupported_rq_types})
end
-- Checks that `box.iproto.override` reset of non-existing request handler is
box.iproto.override(box.iproto.type.PING, nil)
local after = box.stat.net().REQUESTS_IN_PROGRESS.current
t.assert_equals(after - before, 0)
+ end)
+end
+
+-- Start server and set global functions.
+local function init_server(cg, server_env)
+ cg.server = server:new({env = server_env})
+ cg.server:start()
+ cg.server:exec(function(net_box_uri)
+ rawset(_G, 'send_request_and_read_response', function(request_type)
+ local uri = require('uri')
+ local socket = require('socket')
+ -- Connect to the server.
+ local u = uri.parse(net_box_uri)
+ local s = socket.tcp_connect(u.host, u.service)
+ local greeting = s:read(box.iproto.GREETING_SIZE)
+ greeting = box.iproto.decode_greeting(greeting)
+ t.assert_covers(greeting, {protocol = 'Binary'})
+ -- Send the request.
+ local request = box.iproto.encode_packet(
+ {request_type = request_type}, {}
+ )
+ t.assert_equals(s:write(request), #request)
+ -- Read the response.
+ local response = ''
+ local header, body
+ repeat
+ header, body = box.iproto.decode_packet(response)
+ if header == nil then
+ local size = body
+ local data = s:read(size)
+ t.assert_is_not(data)
+ response = response .. data
+ end
+ until header ~= nil
+ s:close()
+ return body[1]
+ end)
+ end, {cg.server.net_box_uri})
+end
+
+-- Delete spaces and triggers.
+local function delete_spaces_and_triggers(cg)
+ cg.server:exec(function()
+ local trigger = require('trigger')
+ if box.space.test then box.space.test:drop() end
+ -- Delete all registered triggers.
+ for event, trigger_list in pairs(trigger.info()) do
+ for _, trigger_descr in pairs(trigger_list) do
+ local trigger_name = trigger_descr[1]
+ trigger.del(event, trigger_name)
+ end
+ end
+ end)
+end
+
+-- Grep server logs for error messages about wrong request types.
+-- Note that event names are case-sensitive.
+local function check_wrong_rq_types(cg)
+ local msg
+ msg = "C> The event `box.iproto.override.' is in IPROTO override " ..
+ "namespace, but `' is not a valid request type"
+ t.assert(cg.server:grep_log(msg))
+ msg = "C> The event `box.iproto.override.pinG' is in IPROTO override " ..
+ "namespace, but `pinG' is not a valid request type"
+ t.assert(cg.server:grep_log(msg))
+ msg = "C> The event `box.iproto.override%[' is in IPROTO override " ..
+ "namespace, but `%[' is not a valid request type"
+ t.assert(cg.server:grep_log(msg))
+ msg = "C> The event `box.iproto.override%[64' is in IPROTO override " ..
+ "namespace, but `%[64' is not a valid request type"
+ t.assert(cg.server:grep_log(msg))
+ msg = "C> The event `box.iproto.override%[ 64%]' is in IPROTO override " ..
+ "namespace, but `%[ 64%]' is not a valid request type"
+ t.assert(cg.server:grep_log(msg))
+ msg = "C> The event `box.iproto.override%[64 %]' is in IPROTO override " ..
+ "namespace, but `%[64 %]' is not a valid request type"
+ t.assert(cg.server:grep_log(msg))
+ msg = "C> The event `box.iproto.override%[64%] ' is in IPROTO override " ..
+ "namespace, but `%[64%] ' is not a valid request type"
+ t.assert(cg.server:grep_log(msg))
+ msg = "C> The event `box.iproto.override%[%-%]' is in IPROTO override " ..
+ "namespace, but `%[%-%]' is not a valid request type"
+ t.assert(cg.server:grep_log(msg))
+ msg = "C> The event `box.iproto.override%[ping%]' is in IPROTO override " ..
+ "namespace, but `%[ping%]' is not a valid request type"
+ t.assert(cg.server:grep_log(msg))
+ msg = "C> The event `box.iproto.override%[64%].ping' is in IPROTO " ..
+ "override namespace, but `%[64%].ping' is not a valid request type"
+ t.assert(cg.server:grep_log(msg))
+end
+
+-- Test IPROTO request handlers override using event triggers, that are set
+-- before `box.cfg{}'. Requests are sent via a raw socket to test the response
+-- on the unknown request types.
+local g2 = t.group('gh-8138-triggers-before-box-cfg')
+
+g2.before_all(function(cg)
+ -- List of unsupported request types, represented as a string.
+ local req_types_str = ''
+ for req in pairs(unsupported_rq_types) do
+ req_types_str = req_types_str .. ("'%s', "):format(req:lower())
+ end
+ -- Set event triggers before `box.cfg{}'.
+ t.assert_equals(box.iproto.type.EXECUTE, 11)
+ local run_before_cfg = ([[
+ local trigger = require('trigger')
+ local function handler_execute()
+ local resp = 'IPROTO_EXECUTE handler, set by name, before box.cfg{}'
+ box.iproto.send(box.session.id(), {}, {resp})
+ return true
+ end
+ local function handler_n11()
+ local resp = 'IPROTO_EXECUTE handler, set by id, before box.cfg{}'
+ box.iproto.send(box.session.id(), {}, {resp})
+ return true
+ end
+ local function handler_ping()
+ local resp = 'IPROTO_PING handler, set by name, before box.cfg{}'
+ box.iproto.send(box.session.id(), {}, {resp})
+ return true
+ end
+ local function handler_n555()
+ local resp = 'IPROTO #555 handler, set by id, before box.cfg{}'
+ box.iproto.send(box.session.id(), {}, {resp})
+ return true
+ end
+ local function handler_unknown()
+ local resp = 'IPROTO_UNKNOWN handler, set by name, before box.cfg{}'
+ box.iproto.send(box.session.id(), {}, {resp})
+ return true
+ end
+ trigger.set('box.iproto.override.execute', 'exec', handler_execute)
+ trigger.set('box.iproto.override[11]', '#11', handler_n11)
+ trigger.set('box.iproto.override.ping', 'ping', handler_ping)
+ trigger.set('box.iproto.override[555]', '#555', handler_n555)
+ trigger.set('box.iproto.override.unknown', 'unk', handler_unknown)
+ -- Set triggers on the unsupported request types.
+ for _, req in pairs({%s}) do
+ trigger.set('box.iproto.override.' .. req, 'unsup', function() end)
+ end
+ -- Set triggers on the wrong request types.
+ trigger.set('box.iproto.override.', 'wrong', function() end)
+ trigger.set('box.iproto.override.pinG', 'wrong', function() end)
+ trigger.set('box.iproto.override[', 'wrong', function() end)
+ trigger.set('box.iproto.override[64', 'wrong', function() end)
+ trigger.set('box.iproto.override[ 64]', 'wrong', function() end)
+ trigger.set('box.iproto.override[64 ]', 'wrong', function() end)
+ trigger.set('box.iproto.override[64] ', 'wrong', function() end)
+ trigger.set('box.iproto.override[-]', 'wrong', function() end)
+ trigger.set('box.iproto.override[ping]', 'wrong', function() end)
+ trigger.set('box.iproto.override[64].ping', 'wrong', function() end)
+ ]]):format(req_types_str)
+ init_server(cg, {['TARANTOOL_RUN_BEFORE_BOX_CFG'] = run_before_cfg})
+end)
+
+g2.after_all(function(cg) cg.server:drop() end)
+g2.after_each(delete_spaces_and_triggers)
+
+-- Check that it is possible to override the handlers using event triggers.
+g2.test_event_triggers = function(cg)
+ -- Grep logs for errors about unsupported and wrong request types.
+ check_unsupported_rq_types(cg)
+ check_wrong_rq_types(cg)
+
+ -- Send correct requests with overridden handlers.
+ cg.server:exec(function()
+ -- Note that IPROTO_EXECUTE is overridden both by id and by name, and
+ -- "by id" handler is always called first.
+ t.assert_equals(
+ _G.send_request_and_read_response(box.iproto.type.EXECUTE),
+ 'IPROTO_EXECUTE handler, set by id, before box.cfg{}')
+ t.assert_equals(
+ _G.send_request_and_read_response(box.iproto.type.PING),
+ 'IPROTO_PING handler, set by name, before box.cfg{}')
+ -- Send an unknown request with a dedicated handler.
+ t.assert_equals(
+ _G.send_request_and_read_response(555),
+ 'IPROTO #555 handler, set by id, before box.cfg{}')
+ -- Send an unknown request without a dedicated handler.
+ t.assert_equals(
+ _G.send_request_and_read_response(666),
+ 'IPROTO_UNKNOWN handler, set by name, before box.cfg{}')
end)
end