[Tarantool-patches] [PATCH 5/9] error: use error_payload in MessagePack codecs

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Sat Nov 6 02:56:36 MSK 2021


Before this patch mp_error API could only encode and decode
hardcoded fields from the C++ classes inheriting struct error.

The fields are gone from the classes in a previous patch - moved
into error_payload. Now to be able to support arbitrary fields in
the payload the MessagePack encoding/decoding must use its content
instead of hardcoded fields depending on error type.

Part of #5568
---
 src/box/error.cc          |   7 --
 src/box/error.h           |  28 +++++-
 src/box/mp_error.cc       | 194 +++++++++++---------------------------
 src/lib/core/diag.c       |  17 ++--
 src/lib/core/diag.h       |   9 ++
 src/lib/core/exception.h  |  66 +++++++++++++
 test/unit/mp_error.cc     |  76 ++++++++++++++-
 test/unit/mp_error.result |  27 +++++-
 8 files changed, 262 insertions(+), 162 deletions(-)

diff --git a/src/box/error.cc b/src/box/error.cc
index 629ec703f..be3b3b6f5 100644
--- a/src/box/error.cc
+++ b/src/box/error.cc
@@ -256,13 +256,6 @@ XlogGapError::XlogGapError(const char *file, unsigned line,
 		 (long long) vclock_sum(to), s_to ? s_to : "");
 }
 
-XlogGapError::XlogGapError(const char *file, unsigned line,
-			   const char *msg)
-		: XlogError(&type_XlogGapError, file, line)
-{
-	error_format_msg(this, "%s", msg);
-}
-
 struct error *
 BuildXlogGapError(const char *file, unsigned line,
 		  const struct vclock *from, const struct vclock *to)
diff --git a/src/box/error.h b/src/box/error.h
index 43faaea70..c2ccf48bb 100644
--- a/src/box/error.h
+++ b/src/box/error.h
@@ -213,6 +213,11 @@ public:
 
 	ClientError(const char *file, unsigned line, uint32_t errcode, ...);
 
+	ClientError()
+		:Exception(&type_ClientError, NULL, 0)
+	{
+	}
+
 	static uint32_t get_errcode(const struct error *e);
 protected:
 	ClientError(const type_info *type, const char *file, unsigned line,
@@ -243,6 +248,11 @@ public:
 			  const char *object_name, const char *user_name,
 			  bool run_trigers = true);
 
+	AccessDeniedError()
+		:ClientError(&type_AccessDeniedError, NULL, 0, 0)
+	{
+	}
+
 	const char *
 	object_type() const
 	{
@@ -276,6 +286,12 @@ struct XlogError: public Exception
 	{
 		error_vformat_msg(this, format, ap);
 	}
+
+	XlogError()
+		:Exception(&type_XlogError, NULL, 0)
+	{
+	}
+
 	XlogError(const struct type_info *type, const char *file,
 		  unsigned line)
 		:Exception(type, file, line)
@@ -289,8 +305,11 @@ struct XlogGapError: public XlogError
 {
 	XlogGapError(const char *file, unsigned line,
 		     const struct vclock *from, const struct vclock *to);
-	XlogGapError(const char *file, unsigned line,
-		     const char *msg);
+
+	XlogGapError()
+		:XlogError(&type_XlogGapError, NULL, 0)
+	{
+	}
 
 	virtual void raise() { throw this; }
 };
@@ -301,6 +320,11 @@ public:
 	CustomError(const char *file, unsigned int line,
 		    const char *custom_type, uint32_t errcode);
 
+	CustomError()
+		:ClientError(&type_CustomError, NULL, 0, 0)
+	{
+	}
+
 	virtual void log() const;
 
 	const char*
diff --git a/src/box/mp_error.cc b/src/box/mp_error.cc
index 35c770400..fba562a84 100644
--- a/src/box/mp_error.cc
+++ b/src/box/mp_error.cc
@@ -118,35 +118,31 @@ struct mp_error {
 	const char *type;
 	const char *file;
 	const char *message;
-	const char *custom_type;
-	const char *ad_object_type;
-	const char *ad_object_name;
-	const char *ad_access_type;
+	struct error_payload payload;
 };
 
 static void
 mp_error_create(struct mp_error *mp_error)
 {
 	memset(mp_error, 0, sizeof(*mp_error));
+	error_payload_create(&mp_error->payload);
+}
+
+static void
+mp_error_destroy(struct mp_error *mp_error)
+{
+	error_payload_destroy(&mp_error->payload);
 }
 
 static uint32_t
 mp_sizeof_error_one(const struct error *error)
 {
 	uint32_t errcode = box_error_code(error);
-
-	bool is_custom = false;
-	bool is_access_denied = false;
-
-	if (strcmp(error->type->name, "CustomError") == 0) {
-		is_custom = true;
-	} else if (strcmp(error->type->name, "AccessDeniedError") == 0) {
-		is_access_denied = true;
-	}
-
-	uint32_t details_num = 6;
+	int field_count = error->payload.count;
+	uint32_t map_size = 6 + (field_count > 0);
 	uint32_t data_size = 0;
 
+	data_size += mp_sizeof_map(map_size);
 	data_size += mp_sizeof_uint(MP_ERROR_TYPE);
 	data_size += mp_sizeof_str(strlen(error->type->name));
 	data_size += mp_sizeof_uint(MP_ERROR_LINE);
@@ -160,28 +156,15 @@ mp_sizeof_error_one(const struct error *error)
 	data_size += mp_sizeof_uint(MP_ERROR_CODE);
 	data_size += mp_sizeof_uint(errcode);
 
-	if (is_access_denied) {
-		++details_num;
-		data_size += mp_sizeof_uint(MP_ERROR_FIELDS);
-		data_size += mp_sizeof_map(3);
-		AccessDeniedError *ad_err = type_cast(AccessDeniedError, error);
-		data_size += mp_sizeof_str(strlen("object_type"));
-		data_size += mp_sizeof_str(strlen(ad_err->object_type()));
-		data_size += mp_sizeof_str(strlen("object_name"));
-		data_size += mp_sizeof_str(strlen(ad_err->object_name()));
-		data_size += mp_sizeof_str(strlen("access_type"));
-		data_size += mp_sizeof_str(strlen(ad_err->access_type()));
-	} else if (is_custom) {
-		++details_num;
+	if (field_count > 0) {
 		data_size += mp_sizeof_uint(MP_ERROR_FIELDS);
-		data_size += mp_sizeof_map(1);
-		data_size += mp_sizeof_str(strlen("custom_type"));
-		data_size +=
-			mp_sizeof_str(strlen(box_error_custom_type(error)));
+		data_size += mp_sizeof_map(field_count);
+		for (int i = 0; i < field_count; ++i) {
+			const struct error_field *f = error->payload.fields[i];
+			data_size += mp_sizeof_str(strlen(f->name));
+			data_size += f->size;
+		}
 	}
-
-	data_size += mp_sizeof_map(details_num);
-
 	return data_size;
 }
 
@@ -195,21 +178,10 @@ static char *
 mp_encode_error_one(char *data, const struct error *error)
 {
 	uint32_t errcode = box_error_code(error);
+	int field_count = error->payload.count;
+	uint32_t map_size = 6 + (field_count > 0);
 
-	bool is_custom = false;
-	bool is_access_denied = false;
-
-	if (strcmp(error->type->name, "CustomError") == 0) {
-		is_custom = true;
-	} else if (strcmp(error->type->name, "AccessDeniedError") == 0) {
-		is_access_denied = true;
-	}
-
-	uint32_t details_num = 6;
-	if (is_access_denied || is_custom)
-		++details_num;
-
-	data = mp_encode_map(data, details_num);
+	data = mp_encode_map(data, map_size);
 	data = mp_encode_uint(data, MP_ERROR_TYPE);
 	data = mp_encode_str0(data, error->type->name);
 	data = mp_encode_uint(data, MP_ERROR_LINE);
@@ -223,21 +195,15 @@ mp_encode_error_one(char *data, const struct error *error)
 	data = mp_encode_uint(data, MP_ERROR_CODE);
 	data = mp_encode_uint(data, errcode);
 
-	if (is_access_denied) {
-		data = mp_encode_uint(data, MP_ERROR_FIELDS);
-		data = mp_encode_map(data, 3);
-		AccessDeniedError *ad_err = type_cast(AccessDeniedError, error);
-		data = mp_encode_str0(data, "object_type");
-		data = mp_encode_str0(data, ad_err->object_type());
-		data = mp_encode_str0(data, "object_name");
-		data = mp_encode_str0(data, ad_err->object_name());
-		data = mp_encode_str0(data, "access_type");
-		data = mp_encode_str0(data, ad_err->access_type());
-	} else if (is_custom) {
+	if (field_count > 0) {
 		data = mp_encode_uint(data, MP_ERROR_FIELDS);
-		data = mp_encode_map(data, 1);
-		data = mp_encode_str0(data, "custom_type");
-		data = mp_encode_str0(data, box_error_custom_type(error));
+		data = mp_encode_map(data, field_count);
+		for (int i = 0; i < field_count; ++i) {
+			const struct error_field *f = error->payload.fields[i];
+			data = mp_encode_str0(data, f->name);
+			memcpy(data, f->data, f->size);
+			data += f->size;
+		}
 	}
 	return data;
 }
@@ -254,72 +220,50 @@ error_build_xc(struct mp_error *mp_error)
 	struct error *err = NULL;
 	if (mp_error->type == NULL || mp_error->message == NULL ||
 	    mp_error->file == NULL) {
-missing_fields:
 		diag_set(ClientError, ER_INVALID_MSGPACK,
 			 "Missing mandatory error fields");
 		return NULL;
 	}
 
 	if (strcmp(mp_error->type, "ClientError") == 0) {
-		err = new ClientError(mp_error->file, mp_error->line,
-				      ER_UNKNOWN);
+		err = new ClientError();
 	} else if (strcmp(mp_error->type, "CustomError") == 0) {
-		if (mp_error->custom_type == NULL)
-			goto missing_fields;
-		err = new CustomError(mp_error->file, mp_error->line,
-				      mp_error->custom_type, mp_error->code);
+		err = new CustomError();
 	} else if (strcmp(mp_error->type, "AccessDeniedError") == 0) {
-		if (mp_error->ad_access_type == NULL ||
-		    mp_error->ad_object_type == NULL ||
-		    mp_error->ad_object_name == NULL)
-			goto missing_fields;
-		err = new AccessDeniedError(mp_error->file, mp_error->line,
-					    mp_error->ad_access_type,
-					    mp_error->ad_object_type,
-					    mp_error->ad_object_name, "",
-					    false);
+		err = new AccessDeniedError();
 	} else if (strcmp(mp_error->type, "XlogError") == 0) {
-		err = new XlogError(&type_XlogError, mp_error->file,
-				    mp_error->line);
+		err = new XlogError();
 	} else if (strcmp(mp_error->type, "XlogGapError") == 0) {
-		err = new XlogGapError(mp_error->file, mp_error->line,
-				       mp_error->message);
+		err = new XlogGapError();
 	} else if (strcmp(mp_error->type, "SystemError") == 0) {
-		err = new SystemError(mp_error->file, mp_error->line,
-				      "%s", mp_error->message);
+		err = new SystemError();
 	} else if (strcmp(mp_error->type, "SocketError") == 0) {
-		err = new SocketError(mp_error->file, mp_error->line, "", "");
-		error_format_msg(err, "%s", mp_error->message);
+		err = new SocketError();
 	} else if (strcmp(mp_error->type, "OutOfMemory") == 0) {
-		err = new OutOfMemory(mp_error->file, mp_error->line,
-				      0, "", "");
+		err = new OutOfMemory();
 	} else if (strcmp(mp_error->type, "TimedOut") == 0) {
-		err = new TimedOut(mp_error->file, mp_error->line);
+		err = new TimedOut();
 	} else if (strcmp(mp_error->type, "ChannelIsClosed") == 0) {
-		err = new ChannelIsClosed(mp_error->file, mp_error->line);
+		err = new ChannelIsClosed();
 	} else if (strcmp(mp_error->type, "FiberIsCancelled") == 0) {
-		err = new FiberIsCancelled(mp_error->file, mp_error->line);
+		err = new FiberIsCancelled();
 	} else if (strcmp(mp_error->type, "LuajitError") == 0) {
-		err = new LuajitError(mp_error->file, mp_error->line,
-				      mp_error->message);
+		err = new LuajitError();
 	} else if (strcmp(mp_error->type, "IllegalParams") == 0) {
-		err = new IllegalParams(mp_error->file, mp_error->line,
-					"%s", mp_error->message);
+		err = new IllegalParams();
 	} else if (strcmp(mp_error->type, "CollationError") == 0) {
-		err = new CollationError(mp_error->file, mp_error->line,
-					 "%s", mp_error->message);
+		err = new CollationError();
 	} else if (strcmp(mp_error->type, "SwimError") == 0) {
-		err = new SwimError(mp_error->file, mp_error->line,
-				    "%s", mp_error->message);
+		err = new SwimError();
 	} else if (strcmp(mp_error->type, "CryptoError") == 0) {
-		err = new CryptoError(mp_error->file, mp_error->line,
-				      "%s", mp_error->message);
+		err = new CryptoError();
 	} else {
-		err = new ClientError(mp_error->file, mp_error->line,
-				      ER_UNKNOWN);
+		err = new ClientError();
 	}
 	err->code = mp_error->code;
 	err->saved_errno = mp_error->saved_errno;
+	error_set_location(err, mp_error->file, mp_error->line);
+	error_move_payload(err, &mp_error->payload);
 	error_format_msg(err, "%s", mp_error->message);
 	return err;
 }
@@ -350,12 +294,6 @@ mp_decode_and_copy_str(const char **data, struct region *region)
 	return region_strdup(region, str, str_len);;
 }
 
-static inline bool
-str_nonterm_is_eq(const char *l, const char *r, uint32_t r_len)
-{
-	return r_len == strlen(l) && memcmp(l, r, r_len) == 0;
-}
-
 static int
 mp_decode_error_fields(const char **data, struct mp_error *mp_err,
 		       struct region *region)
@@ -363,35 +301,16 @@ mp_decode_error_fields(const char **data, struct mp_error *mp_err,
 	if (mp_typeof(**data) != MP_MAP)
 		return -1;
 	uint32_t map_sz = mp_decode_map(data);
-	const char *key;
-	uint32_t key_len;
 	for (uint32_t i = 0; i < map_sz; ++i) {
-		if (mp_typeof(**data) != MP_STR)
+		uint32_t svp = region_used(region);
+		const char *key = mp_decode_and_copy_str(data, region);
+		if (key == NULL)
 			return -1;
-		key = mp_decode_str(data, &key_len);
-		if (str_nonterm_is_eq("object_type", key, key_len)) {
-			mp_err->ad_object_type =
-				mp_decode_and_copy_str(data, region);
-			if (mp_err->ad_object_type == NULL)
-				return -1;
-		} else if (str_nonterm_is_eq("object_name", key, key_len)) {
-			mp_err->ad_object_name =
-				mp_decode_and_copy_str(data, region);
-			if (mp_err->ad_object_name == NULL)
-				return -1;
-		} else if (str_nonterm_is_eq("access_type", key, key_len)) {
-			mp_err->ad_access_type =
-				mp_decode_and_copy_str(data, region);
-			if (mp_err->ad_access_type == NULL)
-				return -1;
-		} else if (str_nonterm_is_eq("custom_type", key, key_len)) {
-			mp_err->custom_type =
-				mp_decode_and_copy_str(data, region);
-			if (mp_err->custom_type == NULL)
-				return -1;
-		} else {
-			mp_next(data);
-		}
+		const char *value = *data;
+		mp_next(data);
+		uint32_t value_len = *data - value;
+		error_payload_set_mp(&mp_err->payload, key, value, value_len);
+		region_truncate(region, svp);
 	}
 	return 0;
 }
@@ -462,6 +381,7 @@ mp_decode_error_one(const char **data)
 	}
 finish:
 	region_truncate(region, region_svp);
+	mp_error_destroy(&mp_err);
 	return err;
 
 error:
diff --git a/src/lib/core/diag.c b/src/lib/core/diag.c
index 217c3ae7e..b6fa1f5bb 100644
--- a/src/lib/core/diag.c
+++ b/src/lib/core/diag.c
@@ -119,18 +119,21 @@ error_create(struct error *e,
 	e->saved_errno = 0;
 	e->code = 0;
 	error_payload_create(&e->payload);
-	if (file != NULL) {
-		snprintf(e->file, sizeof(e->file), "%s", file);
-		e->line = line;
-	} else {
-		e->file[0] = '\0';
-		e->line = 0;
-	}
+	if (file == NULL)
+		file = "";
+	error_set_location(e, file, line);
 	e->errmsg[0] = '\0';
 	e->cause = NULL;
 	e->effect = NULL;
 }
 
+void
+error_set_location(struct error *e, const char *file, int line)
+{
+	snprintf(e->file, sizeof(e->file), "%s", file);
+	e->line = line;
+}
+
 struct diag *
 diag_get(void)
 {
diff --git a/src/lib/core/diag.h b/src/lib/core/diag.h
index 03bd223e1..40d934c19 100644
--- a/src/lib/core/diag.h
+++ b/src/lib/core/diag.h
@@ -190,6 +190,12 @@ error_field_unset(struct error *e, const char *name)
 	error_payload_unset(&e->payload, name);
 }
 
+static inline void
+error_move_payload(struct error *e, struct error_payload *src)
+{
+	error_payload_move(&e->payload, src);
+}
+
 /**
  * Unlink error from its effect. For instance:
  * e1 -> e2 -> e3 -> e4 (e1:set_prev(e2); e2:set_prev(e3) ...)
@@ -243,6 +249,9 @@ error_create(struct error *e,
 	     const struct type_info *type, const char *file,
 	     unsigned line);
 
+void
+error_set_location(struct error *e, const char *file, int line);
+
 void
 error_format_msg(struct error *e, const char *format, ...);
 
diff --git a/src/lib/core/exception.h b/src/lib/core/exception.h
index 7277b2784..28bc7ef05 100644
--- a/src/lib/core/exception.h
+++ b/src/lib/core/exception.h
@@ -91,6 +91,12 @@ public:
 
 	SystemError(const char *file, unsigned line,
 		    const char *format, ...);
+
+	SystemError()
+		:Exception(&type_SystemError, NULL, 0)
+	{
+	}
+
 protected:
 	SystemError(const struct type_info *type, const char *file, unsigned line);
 };
@@ -100,6 +106,12 @@ class SocketError: public SystemError {
 public:
 	SocketError(const char *file, unsigned line, const char *socketname,
 		    const char *format, ...);
+
+	SocketError()
+		:SystemError(&type_SocketError, file, line)
+	{
+	}
+
 	virtual void raise()
 	{
 		throw this;
@@ -111,18 +123,36 @@ public:
 	OutOfMemory(const char *file, unsigned line,
 		    size_t amount, const char *allocator,
 		    const char *object);
+
+	OutOfMemory()
+		:SystemError(&type_OutOfMemory, NULL, 0)
+	{
+	}
+
 	virtual void raise() { throw this; }
 };
 
 class TimedOut: public SystemError {
 public:
 	TimedOut(const char *file, unsigned line);
+
+	TimedOut()
+		:SystemError(&type_TimedOut, NULL, 0)
+	{
+	}
+
 	virtual void raise() { throw this; }
 };
 
 class ChannelIsClosed: public Exception {
 public:
 	ChannelIsClosed(const char *file, unsigned line);
+
+	ChannelIsClosed()
+		:Exception(&type_ChannelIsClosed, NULL, 0)
+	{
+	}
+
 	virtual void raise() { throw this; }
 };
 
@@ -133,6 +163,12 @@ public:
 class FiberIsCancelled: public Exception {
 public:
 	FiberIsCancelled(const char *file, unsigned line);
+
+	FiberIsCancelled()
+		:Exception(&type_FiberIsCancelled, NULL, 0)
+	{
+	}
+
 	virtual void log() const;
 	virtual void raise() { throw this; }
 };
@@ -141,12 +177,24 @@ class LuajitError: public Exception {
 public:
 	LuajitError(const char *file, unsigned line,
 		    const char *msg);
+
+	LuajitError()
+		:Exception(&type_LuajitError, NULL, 0)
+	{
+	}
+
 	virtual void raise() { throw this; }
 };
 
 class IllegalParams: public Exception {
 public:
 	IllegalParams(const char *file, unsigned line, const char *format, ...);
+
+	IllegalParams()
+		:Exception(&type_IllegalParams, NULL, 0)
+	{
+	}
+
 	virtual void raise() { throw this; }
 };
 
@@ -154,18 +202,36 @@ class CollationError: public Exception {
 public:
 	CollationError(const char *file, unsigned line, const char *format,
 		       ...);
+
+	CollationError()
+		:Exception(&type_CollationError, NULL, 0)
+	{
+	}
+
 	virtual void raise() { throw this; }
 };
 
 class SwimError: public Exception {
 public:
 	SwimError(const char *file, unsigned line, const char *format, ...);
+
+	SwimError()
+		:Exception(&type_SwimError, NULL, 0)
+	{
+	}
+
 	virtual void raise() { throw this; }
 };
 
 class CryptoError: public Exception {
 public:
 	CryptoError(const char *file, unsigned line, const char *format, ...);
+
+	CryptoError()
+		:Exception(&type_CryptoError, NULL, 0)
+	{
+	}
+
 	virtual void raise() { throw this; }
 };
 
diff --git a/test/unit/mp_error.cc b/test/unit/mp_error.cc
index fe0cd49b9..e6560883e 100644
--- a/test/unit/mp_error.cc
+++ b/test/unit/mp_error.cc
@@ -34,9 +34,11 @@
 #include "memory.h"
 #include "msgpuck.h"
 #include "mp_extension_types.h"
+#include "random.h"
 #include "tt_static.h"
 #include "small/ibuf.h"
 #include "mpstream/mpstream.h"
+#include "uuid/tt_uuid.h"
 
 #include "box/error.h"
 #include "box/mp_error.h"
@@ -362,7 +364,7 @@ void
 test_fail_not_enough_fields()
 {
 	header();
-	plan(2);
+	plan(4);
 	char buffer[2048];
 	memset(buffer, 0, sizeof(buffer));
 
@@ -383,8 +385,12 @@ test_fail_not_enough_fields()
 	const char *pos = buffer;
 	struct error *unpacked = error_unpack(&pos, len);
 
-	is(unpacked, NULL, "check not enough additional fields");
-	ok(!diag_is_empty(diag_get()), "error about parsing problem is set");
+	isnt(unpacked, NULL, "check lack of fields");
+	is(strcmp(error_field_get_str(unpacked, "object_type"),
+		  err.ad_object_type), 0, "object type");
+	is(strcmp(error_field_get_str(unpacked, "access_type"),
+		  err.ad_access_type), 0, "access type");
+	is(error_field_get_str(unpacked, "object_name"), NULL, "object name");
 	check_plan();
 	footer();
 }
@@ -455,6 +461,65 @@ test_unknown_additional_fields()
 	footer();
 }
 
+static void
+test_payload(void)
+{
+	header();
+	plan(11);
+	char buffer[2048];
+	memset(buffer, 0, sizeof(buffer));
+
+	struct error *e = new ClientError();
+	error_ref(e);
+	e->code = 42;
+	e->saved_errno = 1;
+	error_format_msg(e, "msg");
+	error_set_location(e, "file", 2);
+	error_field_set_str(e, "key1", "1");
+	error_field_set_uint(e, "key2", 1);
+	error_field_set_int(e, "key3", -1);
+	error_field_set_double(e, "key4", 1.5);
+	error_field_set_bool(e, "key5", true);
+	struct tt_uuid uuid;
+	tt_uuid_create(&uuid);
+	error_field_set_uuid(e, "key6", &uuid);
+
+	mp_encode_error(buffer, e);
+	error_unref(e);
+
+	int8_t type;
+	const char *data = buffer;
+	mp_decode_extl(&data, &type);
+	e = error_unpack_unsafe(&data);
+	error_ref(e);
+
+	is(e->code, 42, "code");
+	is(e->saved_errno, 1, "errno");
+	is(strcmp(e->errmsg, "msg"), 0, "msg");
+	is(e->line, 2, "line");
+	is(strcmp(e->file, "file"), 0, "file");
+	is(strcmp(error_field_get_str(e, "key1"), "1"), 0, "key str");
+	uint64_t val_uint;
+	ok(error_field_get_uint(e, "key2", &val_uint) && val_uint == 1,
+	   "key uint");
+	int64_t val_int;
+	ok(error_field_get_int(e, "key3", &val_int) && val_int == -1,
+	   "key int");
+	double val_dbl;
+	ok(error_field_get_double(e, "key4", &val_dbl) && val_dbl == 1.5,
+	   "key double");
+	bool val_bool;
+	ok(error_field_get_bool(e, "key5", &val_bool) && val_bool, "key bool");
+	struct tt_uuid val_uuid;
+	ok(error_field_get_uuid(e, "key6", &val_uuid) &&
+	   tt_uuid_is_equal(&uuid, &val_uuid), "key uuid");
+
+	error_unref(e);
+
+	check_plan();
+	footer();
+}
+
 static int
 mp_fprint_ext_test(FILE *file, const char **data, int depth)
 {
@@ -723,7 +788,8 @@ int
 main(void)
 {
 	header();
-	plan(6);
+	plan(7);
+	random_init();
 	memory_init();
 	fiber_init(fiber_c_invoke);
 
@@ -732,10 +798,12 @@ main(void)
 	test_fail_not_enough_fields();
 	test_unknown_fields();
 	test_unknown_additional_fields();
+	test_payload();
 	test_mp_print();
 
 	fiber_free();
 	memory_free();
+	random_free();
 	footer();
 	return check_plan();
 }
diff --git a/test/unit/mp_error.result b/test/unit/mp_error.result
index 0582458d3..356d2dc97 100644
--- a/test/unit/mp_error.result
+++ b/test/unit/mp_error.result
@@ -1,5 +1,5 @@
 	*** main ***
-1..6
+1..7
 	*** test_stack_error_decode ***
     1..17
     ok 1 - check CustomError
@@ -27,9 +27,11 @@ ok 1 - subtests
 ok 2 - subtests
 	*** test_decode_unknown_type: done ***
 	*** test_fail_not_enough_fields ***
-    1..2
-    ok 1 - check not enough additional fields
-    ok 2 - error about parsing problem is set
+    1..4
+    ok 1 - check lack of fields
+    ok 2 - object type
+    ok 3 - access type
+    ok 4 - object name
 ok 3 - subtests
 	*** test_fail_not_enough_fields: done ***
 	*** test_unknown_fields ***
@@ -41,6 +43,21 @@ ok 4 - subtests
     ok 1 - check unknown additional field
 ok 5 - subtests
 	*** test_unknown_additional_fields: done ***
+	*** test_payload ***
+    1..11
+    ok 1 - code
+    ok 2 - errno
+    ok 3 - msg
+    ok 4 - line
+    ok 5 - file
+    ok 6 - key str
+    ok 7 - key uint
+    ok 8 - key int
+    ok 9 - key double
+    ok 10 - key bool
+    ok 11 - key uuid
+ok 6 - subtests
+	*** test_payload: done ***
 	*** test_mp_print ***
     1..60
     # zero depth, normal error
@@ -109,6 +126,6 @@ ok 5 - subtests
     ok 58 - mp_fprint depth 0 correct length
     ok 59 - mp_fprint depth 0 correct prefix and suffix
     ok 60 - mp_fprint depth 0 correct object in the middle
-ok 6 - subtests
+ok 7 - subtests
 	*** test_mp_print: done ***
 	*** main: done ***
-- 
2.24.3 (Apple Git-128)



More information about the Tarantool-patches mailing list