mirror of https://github.com/neutrinolabs/xrdp
Add libipm test suite
This commit is contained in:
parent
e059336dff
commit
6cf053c9df
|
@ -587,6 +587,17 @@ g_sck_local_socket(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_sck_local_socketpair(int sck[2])
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return -1;
|
||||
#else
|
||||
return socketpair(PF_LOCAL, SOCK_STREAM, 0, sck);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_sck_vsock_socket(void)
|
||||
|
|
|
@ -71,6 +71,7 @@ int g_sck_get_send_buffer_bytes(int sck, int *bytes);
|
|||
int g_sck_set_recv_buffer_bytes(int sck, int bytes);
|
||||
int g_sck_get_recv_buffer_bytes(int sck, int *bytes);
|
||||
int g_sck_local_socket(void);
|
||||
int g_sck_local_socketpair(int sck[2]);
|
||||
int g_sck_vsock_socket(void);
|
||||
int g_sck_get_peer_cred(int sck, int *pid, int *uid, int *gid);
|
||||
void g_sck_close(int sck);
|
||||
|
|
|
@ -498,6 +498,7 @@ AC_CONFIG_FILES([
|
|||
sesman/tools/Makefile
|
||||
tests/Makefile
|
||||
tests/common/Makefile
|
||||
tests/libipm/Makefile
|
||||
tests/libxrdp/Makefile
|
||||
tests/memtest/Makefile
|
||||
tests/xrdp/Makefile
|
||||
|
|
|
@ -4,6 +4,7 @@ EXTRA_DIST = \
|
|||
|
||||
SUBDIRS = \
|
||||
common \
|
||||
libipm \
|
||||
libxrdp \
|
||||
memtest \
|
||||
xrdp
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_srcdir)/libipm \
|
||||
-I$(top_srcdir)/common
|
||||
|
||||
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
|
||||
$(top_srcdir)/tap-driver.sh
|
||||
|
||||
PACKAGE_STRING = "libipm"
|
||||
|
||||
TESTS = test_libipm
|
||||
check_PROGRAMS = test_libipm
|
||||
|
||||
test_libipm_SOURCES = \
|
||||
test_libipm_main.c \
|
||||
test_libipm.h \
|
||||
test_libipm_send_calls.c \
|
||||
test_libipm_recv_calls.c
|
||||
|
||||
test_libipm_CFLAGS = \
|
||||
@CHECK_CFLAGS@ \
|
||||
-D TOP_SRCDIR=\"$(top_srcdir)\"
|
||||
|
||||
test_libipm_LDADD = \
|
||||
$(top_builddir)/libipm/libipm.la \
|
||||
$(top_builddir)/common/libcommon.la \
|
||||
@CHECK_LIBS@
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
#ifndef TEST_LIBIPM__H
|
||||
#define TEST_LIBIPM__H
|
||||
|
||||
#include <check.h>
|
||||
|
||||
/* Private libipm stuff. This is duplicated here, so if the libipm
|
||||
* value change, tests will fail! */
|
||||
enum
|
||||
{
|
||||
LIBIPM_VERSION = 2,
|
||||
LIBIPM_HEADER_SIZE = 12,
|
||||
LIBIPM_MAX_MESSAGE_SIZE = 8192,
|
||||
LIBIPM_MAX_PAYLOAD_SIZE = LIBIPM_MAX_MESSAGE_SIZE - LIBIPM_HEADER_SIZE
|
||||
};
|
||||
|
||||
/* Globals */
|
||||
extern struct trans *g_t_out; /* Channel for outputting libipm messages */
|
||||
extern struct trans *g_t_in; /* Channel for inputting libipm messages */
|
||||
extern struct trans *g_t_vanilla; /* Non-SCP channel */
|
||||
|
||||
extern const char *g_supported_types; /* All recognised type codes */
|
||||
extern const char *g_unimplemented_types; /* recognised, unimplemented codes */
|
||||
|
||||
#define TEST_MESSAGE_NO 66
|
||||
/* Test message with no string translation */
|
||||
#define TEST_MESSAGE_NO_STRING_NO 67
|
||||
|
||||
/**
|
||||
* Compares two binary blocks
|
||||
*
|
||||
* @param actual_data Actual data
|
||||
* @param actual_len Actual length
|
||||
* @param expected_data Expected data
|
||||
* @aram expected_len Expected data length
|
||||
*
|
||||
* Differences are raised using ck_* calls
|
||||
*/
|
||||
void
|
||||
check_binary_data_eq(const void *actual_data,
|
||||
unsigned int actual_len,
|
||||
const void *expected_data,
|
||||
unsigned int expected_len);
|
||||
|
||||
/**
|
||||
* Looks for the specified string in the specified stream
|
||||
* @param s Stream to search
|
||||
* @param str Null-terminated string to look for
|
||||
* @return != 0 if string found in the buffer
|
||||
*
|
||||
* The whole buffer is searched for the string. not just the
|
||||
* used bit.
|
||||
*/
|
||||
int
|
||||
does_stream_contain_string(const struct stream *s, const char *str);
|
||||
|
||||
Suite *make_suite_test_libipm_send_calls(void);
|
||||
Suite *make_suite_test_libipm_recv_calls(void);
|
||||
|
||||
#endif /* TEST_LIBIPM__H */
|
|
@ -0,0 +1,194 @@
|
|||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "libipm.h"
|
||||
#include "trans.h"
|
||||
#include "os_calls.h"
|
||||
#include "string_calls.h"
|
||||
|
||||
#include "test_libipm.h"
|
||||
|
||||
struct trans *g_t_out = NULL;
|
||||
struct trans *g_t_in = NULL;
|
||||
struct trans *g_t_vanilla = NULL;
|
||||
|
||||
const char *g_supported_types = "ybnqiuxtsdhogB";
|
||||
const char *g_unimplemented_types = "dhog";
|
||||
|
||||
/******************************************************************************/
|
||||
static const char *
|
||||
msgno_to_str(unsigned short msgno)
|
||||
{
|
||||
return (msgno == TEST_MESSAGE_NO) ? "TEST_MESSAGE_NO" : NULL;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static void
|
||||
suite_test_libipm_calls_start(void)
|
||||
{
|
||||
int sck[2];
|
||||
int istatus;
|
||||
struct trans *t1 = NULL;
|
||||
struct trans *t2 = NULL;
|
||||
struct trans *t3 = NULL;
|
||||
int success = 0;
|
||||
|
||||
if ((t1 = trans_create(TRANS_MODE_UNIX, 128, 128)) == NULL)
|
||||
{
|
||||
const char *errstr = g_get_strerror();
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create test transport 1 [%s]", errstr);
|
||||
}
|
||||
else if ((t2 = trans_create(TRANS_MODE_UNIX, 128, 128)) == NULL)
|
||||
{
|
||||
const char *errstr = g_get_strerror();
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create test transport 2 [%s]", errstr);
|
||||
}
|
||||
else if ((t3 = trans_create(TRANS_MODE_UNIX, 128, 128)) == NULL)
|
||||
{
|
||||
const char *errstr = g_get_strerror();
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create test transport 3 [%s]", errstr);
|
||||
}
|
||||
else if ((istatus = g_sck_local_socketpair(sck)) < 0)
|
||||
{
|
||||
const char *errstr = g_get_strerror();
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create test sockets [%s]", errstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
enum libipm_status init1;
|
||||
enum libipm_status init2;
|
||||
|
||||
g_sck_set_non_blocking(sck[1]);
|
||||
|
||||
t1->sck = sck[0];
|
||||
t1->type1 = TRANS_TYPE_CLIENT;
|
||||
t1->status = TRANS_STATUS_UP;
|
||||
|
||||
t2->sck = sck[1];
|
||||
t2->type1 = TRANS_TYPE_SERVER;
|
||||
t2->status = TRANS_STATUS_UP;
|
||||
|
||||
init1 = libipm_init_trans(t1, LIBIPM_FAC_TEST, msgno_to_str);
|
||||
init2 = libipm_init_trans(t2, LIBIPM_FAC_TEST, msgno_to_str);
|
||||
if (init1 != E_LI_SUCCESS || init2 != E_LI_SUCCESS)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "libipm_init_trans() call failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
success = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
g_t_out = t1;
|
||||
g_t_in = t2;
|
||||
g_t_vanilla = t3;
|
||||
}
|
||||
else
|
||||
{
|
||||
trans_delete(t1);
|
||||
trans_delete(t2);
|
||||
trans_delete(t3);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static void
|
||||
suite_test_libipm_calls_end(void)
|
||||
{
|
||||
trans_delete(g_t_out);
|
||||
trans_delete(g_t_in);
|
||||
trans_delete(g_t_vanilla);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
check_binary_data_eq(const void *actual_data,
|
||||
unsigned int actual_len,
|
||||
const void *expected_data,
|
||||
unsigned int expected_len)
|
||||
{
|
||||
const unsigned char *cp_expected = (const unsigned char *)expected_data;
|
||||
const unsigned char *cp_expected_end =
|
||||
(const unsigned char *)expected_data + expected_len;
|
||||
const unsigned char *cp_actual = (const unsigned char *)actual_data;
|
||||
|
||||
if (expected_len != actual_len)
|
||||
{
|
||||
ck_abort_msg("Differing lengths. Expected %u, got %u",
|
||||
expected_len, actual_len);
|
||||
}
|
||||
|
||||
while (cp_expected < cp_expected_end)
|
||||
{
|
||||
if (*cp_expected != *cp_actual)
|
||||
{
|
||||
int byte_pos = cp_expected - (const unsigned char *)expected_data;
|
||||
ck_abort_msg("Byte position %d. Expected %02x, got %02x",
|
||||
byte_pos, *cp_expected, *cp_actual);
|
||||
}
|
||||
++cp_expected;
|
||||
++cp_actual;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int
|
||||
does_stream_contain_string(const struct stream *s, const char *str)
|
||||
{
|
||||
int len = g_strlen(str);
|
||||
int i;
|
||||
if (len > 0 && len <= s->size)
|
||||
{
|
||||
for (i = 0 ; i <= s->size - len; ++i)
|
||||
{
|
||||
/* This is not a sophisticated string search. We use a
|
||||
* single character test to avoid a function call for
|
||||
* every comparison */
|
||||
if (str[0] == s->data[i] && g_memcmp(str, &s->data[i], len) == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
int main (void)
|
||||
{
|
||||
int number_failed;
|
||||
SRunner *sr;
|
||||
|
||||
sr = srunner_create (make_suite_test_libipm_send_calls());
|
||||
srunner_add_suite (sr, make_suite_test_libipm_recv_calls());
|
||||
|
||||
srunner_set_tap(sr, "-");
|
||||
/*
|
||||
* Set up console logging */
|
||||
struct log_config *lc = log_config_init_for_console(LOG_LEVEL_INFO, NULL);
|
||||
log_start_from_param(lc);
|
||||
log_config_free(lc);
|
||||
|
||||
/* Initialise modules */
|
||||
suite_test_libipm_calls_start();
|
||||
|
||||
srunner_run_all (sr, CK_ENV);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
suite_test_libipm_calls_end();
|
||||
|
||||
log_end();
|
||||
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
|
@ -0,0 +1,857 @@
|
|||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libipm.h"
|
||||
#include "os_calls.h"
|
||||
#include "string_calls.h"
|
||||
#include "trans.h"
|
||||
|
||||
#include "test_libipm.h"
|
||||
|
||||
/* Random(ish) values for test_libipm_send_recv_all_test */
|
||||
#define TEST_y_VALUE 89
|
||||
#define TEST_b_VALUE 1
|
||||
#define TEST_n_VALUE -143
|
||||
#define TEST_q_VALUE 329
|
||||
#define TEST_i_VALUE -150000
|
||||
#define TEST_u_VALUE 150000
|
||||
#define TEST_x_VALUE -4500000000L
|
||||
#define TEST_t_VALUE 8500000000L
|
||||
#define TEST_s_VALUE "libipm recv test"
|
||||
#define TEST_B_VALUE 'b', 'y', 'B', 'Y', '8', '2', '/'
|
||||
|
||||
/**
|
||||
* Type for fields in the message header
|
||||
*
|
||||
* The type value is the offset of the field within the header
|
||||
*/
|
||||
enum header_field
|
||||
{
|
||||
HDR_IPM_VER = 0,
|
||||
HDR_MSG_LEN = 2,
|
||||
HDR_FACILITY = 4,
|
||||
HDR_MSGNO = 6,
|
||||
HDR_RESERVED = 8
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a message header field value */
|
||||
static unsigned int
|
||||
get_header_field(struct stream *s, enum header_field field)
|
||||
{
|
||||
unsigned int res;
|
||||
char *saved_p = s->p;
|
||||
s->p = s->data + (unsigned short)field;
|
||||
if (field == HDR_RESERVED)
|
||||
{
|
||||
in_uint32_le(s, res);
|
||||
}
|
||||
else
|
||||
{
|
||||
in_uint16_le(s, res);
|
||||
}
|
||||
|
||||
s->p = saved_p;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a message header field value */
|
||||
static void
|
||||
set_header_field(struct stream *s, enum header_field field, unsigned int val)
|
||||
{
|
||||
char *saved_p = s->p;
|
||||
s->p = s->data + (unsigned short)field;
|
||||
if (field == HDR_RESERVED)
|
||||
{
|
||||
out_uint32_le(s, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
out_uint16_le(s, val);
|
||||
}
|
||||
|
||||
s->p = saved_p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes input on a non-blocking socket
|
||||
*
|
||||
* Returns number of bytes read
|
||||
*/
|
||||
static unsigned int
|
||||
flush_socket(int sck)
|
||||
{
|
||||
char buff[1024];
|
||||
unsigned int result = 0;
|
||||
int status;
|
||||
while (1)
|
||||
{
|
||||
status = g_sck_recv(g_t_in->sck, buff, sizeof(buff), 0);
|
||||
if (status < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
result += status;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for an expected incoming message */
|
||||
static void
|
||||
check_for_incoming_message(unsigned short expected_msgno)
|
||||
{
|
||||
enum libipm_status status;
|
||||
unsigned short msgno;
|
||||
|
||||
/* Get the message at the other end */
|
||||
libipm_msg_in_reset(g_t_in);
|
||||
status = libipm_msg_in_wait_available(g_t_in);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
msgno = libipm_msg_in_start(g_t_in);
|
||||
ck_assert_int_eq(msgno, expected_msgno);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for input truncated by a number of bytes
|
||||
*
|
||||
* This call assumes the output buffer contains a message of a single
|
||||
* type that has already been successfully sent and checked.
|
||||
*
|
||||
* The send size is truncated, and the message is sent again. This
|
||||
* lets us check the input parser won't accept a type for which
|
||||
* there is insufficient data.
|
||||
*/
|
||||
static void
|
||||
test_truncated_input_type(char typechar, void *valueptr,
|
||||
int truncate_value,
|
||||
enum libipm_status expected_status)
|
||||
|
||||
{
|
||||
const char format[] = {typechar, '\0'};
|
||||
enum libipm_status status;
|
||||
int istatus;
|
||||
unsigned int msg_size;
|
||||
|
||||
/* The same message is still in the buffer.
|
||||
*
|
||||
* reduce the payload length by the truncate value...*/
|
||||
msg_size = get_header_field(g_t_out->out_s, HDR_MSG_LEN);
|
||||
set_header_field(g_t_out->out_s, HDR_MSG_LEN, msg_size - truncate_value);
|
||||
|
||||
/* ...and re-send it */
|
||||
istatus = trans_force_write(g_t_out);
|
||||
ck_assert_int_eq(istatus, 0);
|
||||
|
||||
/* Catch the message at the other end */
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
switch (typechar)
|
||||
{
|
||||
case 'B':
|
||||
/* For this type, the descriptor is critical to read
|
||||
* the value */
|
||||
status = libipm_msg_in_parse(g_t_in, format,
|
||||
(struct fsb_type *)valueptr);
|
||||
break;
|
||||
default:
|
||||
/* For other types, the value shouldn't be needed, as
|
||||
* it's only written to if the parse is successful */
|
||||
status = libipm_msg_in_parse(g_t_in, format,
|
||||
(struct fsb_type *)NULL);
|
||||
break;
|
||||
}
|
||||
ck_assert_int_eq(status, expected_status);
|
||||
|
||||
/* There should be 'truncate_value' extra octets left on the input
|
||||
* socket which wasn't read when we shrunk the header */
|
||||
istatus = flush_socket(g_t_in->sck);
|
||||
ck_assert_int_eq(istatus, truncate_value);
|
||||
|
||||
/* Put the message size back to its original value, for further tests */
|
||||
set_header_field(g_t_out->out_s, HDR_MSG_LEN, msg_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for bad header values
|
||||
*
|
||||
* This call assumes the output buffer contains a message containing
|
||||
* a single 'u' type that has already been send and checked
|
||||
*
|
||||
* The specified header field is overwritten, and the message is
|
||||
* sent. On the receive side we check for a 'bad header' error, and
|
||||
* then put everything back to its starting place.
|
||||
*/
|
||||
static void
|
||||
test_bad_header_value(enum header_field field, unsigned int test_val)
|
||||
{
|
||||
unsigned int old_val;
|
||||
enum libipm_status status;
|
||||
int istatus;
|
||||
|
||||
/* The same message is still in the buffer.
|
||||
*
|
||||
* Save the field value we are going to change, and replace it */
|
||||
old_val = get_header_field(g_t_out->out_s, field);
|
||||
set_header_field(g_t_out->out_s, field, test_val);
|
||||
|
||||
/* re-send the message */
|
||||
istatus = trans_force_write(g_t_out);
|
||||
ck_assert_int_eq(istatus, 0);
|
||||
|
||||
/* Catch the message at the other end. The error is
|
||||
* reported when we wait for the incoming message */
|
||||
libipm_msg_in_reset(g_t_in);
|
||||
status = libipm_msg_in_wait_available(g_t_in);
|
||||
ck_assert_int_eq(status, E_LI_BAD_HEADER);
|
||||
|
||||
/* There should be 5 extra octets ('u' + 32-bit value) left on the input
|
||||
* socket which wasn't read when we broke the header */
|
||||
istatus = flush_socket(g_t_in->sck);
|
||||
ck_assert_int_eq(istatus, 1 + sizeof(uint32_t));
|
||||
|
||||
/* Put the message size back to its original value, for further tests */
|
||||
set_header_field(g_t_out->out_s, field, old_val);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* As the 'append all' test, but data is sent across a link, demarshalled,
|
||||
* and validated */
|
||||
START_TEST(test_libipm_send_recv_all_test)
|
||||
{
|
||||
ck_assert_ptr_ne(g_t_out, NULL);
|
||||
ck_assert_ptr_ne(g_t_in, NULL);
|
||||
|
||||
static char bin_out[] = { TEST_B_VALUE };
|
||||
struct libipm_fsb binary_desc = { (void *)bin_out, sizeof(bin_out) };
|
||||
enum libipm_status status;
|
||||
|
||||
/* variables for received values */
|
||||
uint8_t y;
|
||||
int b;
|
||||
int16_t n;
|
||||
uint16_t q;
|
||||
int32_t i;
|
||||
uint32_t u;
|
||||
int64_t x;
|
||||
uint64_t t;
|
||||
char *s;
|
||||
char B[sizeof(bin_out)];
|
||||
char c;
|
||||
|
||||
/* The message is small enough to fit in the socket buffer */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO,
|
||||
"ybnqiuxtsB",
|
||||
TEST_y_VALUE,
|
||||
TEST_b_VALUE,
|
||||
TEST_n_VALUE,
|
||||
TEST_q_VALUE,
|
||||
TEST_i_VALUE,
|
||||
TEST_u_VALUE,
|
||||
TEST_x_VALUE,
|
||||
TEST_t_VALUE,
|
||||
TEST_s_VALUE,
|
||||
&binary_desc);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
/* Catch the message at the other end */
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Re-use our descriptor for the receive operation */
|
||||
binary_desc.data = (void *)&B;
|
||||
binary_desc.datalen = sizeof(B);
|
||||
|
||||
status = libipm_msg_in_parse(
|
||||
g_t_in,
|
||||
"ybnqiuxtsB",
|
||||
&y, &b, &n, &q, &i, &u, &x, &t, &s, &binary_desc);
|
||||
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(y, TEST_y_VALUE);
|
||||
ck_assert_int_eq(b, TEST_b_VALUE);
|
||||
ck_assert_int_eq(n, TEST_n_VALUE);
|
||||
ck_assert_int_eq(q, TEST_q_VALUE);
|
||||
ck_assert_int_eq(i, TEST_i_VALUE);
|
||||
ck_assert_int_eq(u, TEST_u_VALUE);
|
||||
ck_assert_int_eq(x, TEST_x_VALUE);
|
||||
ck_assert_int_eq(t, TEST_t_VALUE);
|
||||
check_binary_data_eq(TEST_s_VALUE, sizeof(TEST_s_VALUE) - 1,
|
||||
s, g_strlen(s));
|
||||
check_binary_data_eq(bin_out, sizeof(bin_out), B, sizeof(B));
|
||||
|
||||
/* Check we're at the end of the message */
|
||||
c = libipm_msg_in_peek_type(g_t_in);
|
||||
ck_assert_int_eq(c, '\0');
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various receive errors for 'y'
|
||||
*/
|
||||
START_TEST(test_libipm_receive_y_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
uint8_t y;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "y", TEST_y_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "y", &y);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(y, TEST_y_VALUE);
|
||||
|
||||
test_truncated_input_type('y', &y, 1, E_LI_BUFFER_OVERFLOW);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various receive errors for 'b'
|
||||
*/
|
||||
START_TEST(test_libipm_receive_b_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
int b;
|
||||
int istatus;
|
||||
char c;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "b", TEST_b_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "b", &b);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(b, TEST_b_VALUE);
|
||||
|
||||
test_truncated_input_type('b', &b, 1, E_LI_BUFFER_OVERFLOW);
|
||||
|
||||
/* Resend and re-catch the message */
|
||||
istatus = trans_force_write(g_t_out);
|
||||
ck_assert_int_eq(istatus, 0);
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Modify the message to contain a '2' for the boolean */
|
||||
c = libipm_msg_in_peek_type(g_t_in);
|
||||
ck_assert_int_eq(c, 'b'); /* Next type should be a 'b' */
|
||||
c = *(g_t_in->in_s->p + 1); /* This should be the test value */
|
||||
ck_assert_int_eq(c, TEST_b_VALUE); /* Check it */
|
||||
*(g_t_in->in_s->p + 1) = 2;
|
||||
status = libipm_msg_in_parse( g_t_in, "b", &b);
|
||||
ck_assert_int_eq(status, E_LI_BAD_VALUE);
|
||||
|
||||
/* Resend and re-catch the message */
|
||||
istatus = trans_force_write(g_t_out);
|
||||
ck_assert_int_eq(istatus, 0);
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Modify the message to contain a '-1' for the boolean */
|
||||
*(g_t_in->in_s->p + 1) = (char) -1;
|
||||
status = libipm_msg_in_parse( g_t_in, "b", &b);
|
||||
ck_assert_int_eq(status, E_LI_BAD_VALUE);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various receive errors for 'n'
|
||||
*/
|
||||
START_TEST(test_libipm_receive_n_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
int16_t n;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "n", TEST_n_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "n", &n);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(n, TEST_n_VALUE);
|
||||
|
||||
test_truncated_input_type('n', &n, 1, E_LI_BUFFER_OVERFLOW);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various receive errors for 'q'
|
||||
*/
|
||||
START_TEST(test_libipm_receive_q_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
uint16_t q;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "q", TEST_q_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "q", &q);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(q, TEST_q_VALUE);
|
||||
|
||||
test_truncated_input_type('q', &q, 1, E_LI_BUFFER_OVERFLOW);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various receive errors for 'i'
|
||||
*/
|
||||
START_TEST(test_libipm_receive_i_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
int32_t i;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "i", TEST_i_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "i", &i);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(i, TEST_i_VALUE);
|
||||
|
||||
test_truncated_input_type('i', &i, 1, E_LI_BUFFER_OVERFLOW);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various receive errors for 'u'
|
||||
*/
|
||||
START_TEST(test_libipm_receive_u_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
uint32_t u;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "u", TEST_u_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "u", &u);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(u, TEST_u_VALUE);
|
||||
|
||||
test_truncated_input_type('u', &u, 1, E_LI_BUFFER_OVERFLOW);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various receive errors for 'x'
|
||||
*/
|
||||
START_TEST(test_libipm_receive_x_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
int64_t x;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "x", TEST_x_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "x", &x);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(x, TEST_x_VALUE);
|
||||
|
||||
test_truncated_input_type('x', &x, 1, E_LI_BUFFER_OVERFLOW);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various receive errors for 't'
|
||||
*/
|
||||
START_TEST(test_libipm_receive_t_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
uint64_t t;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "t", TEST_t_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "t", &t);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(t, TEST_t_VALUE);
|
||||
|
||||
test_truncated_input_type('t', &t, 1, E_LI_BUFFER_OVERFLOW);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various receive errors for 's'
|
||||
*/
|
||||
START_TEST(test_libipm_receive_s_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
char *s;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "s", TEST_s_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "s", &s);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
check_binary_data_eq(TEST_s_VALUE, sizeof(TEST_s_VALUE) - 1,
|
||||
s, g_strlen(s));
|
||||
|
||||
/* This effectively tests that unterminated strings are not
|
||||
* passed back to the user */
|
||||
test_truncated_input_type('s', &s, 1, E_LI_BAD_VALUE);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various receive errors for 's'
|
||||
*/
|
||||
START_TEST(test_libipm_receive_B_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
static char bin_out[] = { TEST_B_VALUE };
|
||||
char bin_in[sizeof(bin_out)];
|
||||
|
||||
struct libipm_fsb binary_desc = { (void *)bin_out, sizeof(bin_out) };
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "B", &binary_desc);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
binary_desc.data = (void *)bin_in;
|
||||
binary_desc.datalen = sizeof(bin_in);
|
||||
|
||||
status = libipm_msg_in_parse( g_t_in, "B", &binary_desc);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
check_binary_data_eq(bin_out, sizeof(bin_out),
|
||||
bin_in, sizeof(bin_in));
|
||||
|
||||
/* Check a truncated binary object is rejected */
|
||||
test_truncated_input_type('B', &binary_desc, 1, E_LI_BUFFER_OVERFLOW);
|
||||
|
||||
/* Check a binary object without a complete length field is rejected */
|
||||
test_truncated_input_type('B', &binary_desc, sizeof(bin_out) + 1,
|
||||
E_LI_BUFFER_OVERFLOW);
|
||||
|
||||
/* Check a binary object with a mismatching FSB length field is rejected */
|
||||
--binary_desc.datalen;
|
||||
test_truncated_input_type('B', &binary_desc, 0, E_LI_BAD_VALUE);
|
||||
++binary_desc.datalen;
|
||||
|
||||
/* Check a binary object with a null FSB data field is rejected */
|
||||
binary_desc.data = NULL;
|
||||
test_truncated_input_type('B', &binary_desc, 0, E_LI_PROGRAM_ERROR);
|
||||
test_truncated_input_type('B', NULL, 0, E_LI_PROGRAM_ERROR);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks for a message with a completely missing type
|
||||
*/
|
||||
START_TEST(test_libipm_receive_no_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
uint32_t u;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "u", TEST_u_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "u", &u);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(u, TEST_u_VALUE);
|
||||
|
||||
/* Completely remove the type flag and the value from the message */
|
||||
test_truncated_input_type('u', &u, sizeof(uint32_t) + 1,
|
||||
E_LI_BUFFER_OVERFLOW);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks for a message with an unexpected type
|
||||
*/
|
||||
START_TEST(test_libipm_receive_unexpected_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
int istatus;
|
||||
uint32_t u;
|
||||
int32_t i;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "u", TEST_u_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "u", &u);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(u, TEST_u_VALUE);
|
||||
|
||||
/* Resend and re-catch the message */
|
||||
istatus = trans_force_write(g_t_out);
|
||||
ck_assert_int_eq(istatus, 0);
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Try parsing with a type mismatch */
|
||||
status = libipm_msg_in_parse( g_t_in, "i", &i);
|
||||
ck_assert_int_eq(status, E_LI_UNEXPECTED_TYPE);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks for a message with an unsupported type
|
||||
*/
|
||||
START_TEST(test_libipm_receive_unsupported_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
int istatus;
|
||||
uint32_t u;
|
||||
char c;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "u", TEST_u_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "u", &u);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(u, TEST_u_VALUE);
|
||||
|
||||
/* Resend and re-catch the message */
|
||||
istatus = trans_force_write(g_t_out);
|
||||
ck_assert_int_eq(istatus, 0);
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Modify the message to contain an unsupported type */
|
||||
c = libipm_msg_in_peek_type(g_t_in);
|
||||
ck_assert_int_eq(c, 'u'); /* Next type should be a 'u' */
|
||||
*g_t_in->in_s->p = 'A'; /* unsupported type */
|
||||
c = libipm_msg_in_peek_type(g_t_in);
|
||||
ck_assert_int_eq(c, '?'); /* peek should say this is an error */
|
||||
|
||||
status = libipm_msg_in_parse( g_t_in, "A", NULL); /* Parse it anyway */
|
||||
ck_assert_int_eq(status, E_LI_UNSUPPORTED_TYPE);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks for a message with an unimplemented type
|
||||
*/
|
||||
START_TEST(test_libipm_receive_unimplemented_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
int istatus;
|
||||
uint32_t u;
|
||||
char c;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO_STRING_NO, "u", TEST_u_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO_STRING_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "u", &u);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(u, TEST_u_VALUE);
|
||||
|
||||
/* Resend and re-catch the message */
|
||||
istatus = trans_force_write(g_t_out);
|
||||
ck_assert_int_eq(istatus, 0);
|
||||
check_for_incoming_message(TEST_MESSAGE_NO_STRING_NO);
|
||||
|
||||
/* Try parsing with an unimplemented type.
|
||||
* To do this we need to modify the type marker in the input stream */
|
||||
c = libipm_msg_in_peek_type(g_t_in);
|
||||
ck_assert_int_eq(c, 'u'); /* Next type should be a 'u' */
|
||||
*g_t_in->in_s->p = 'd'; /* reserved type */
|
||||
c = libipm_msg_in_peek_type(g_t_in);
|
||||
ck_assert_int_eq(c, 'd');
|
||||
status = libipm_msg_in_parse( g_t_in, "d", NULL);
|
||||
ck_assert_int_eq(status, E_LI_UNIMPLEMENTED_TYPE);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks for bad header values
|
||||
*/
|
||||
START_TEST(test_libipm_receive_bad_header)
|
||||
{
|
||||
enum libipm_status status;
|
||||
uint32_t u;
|
||||
unsigned short hdr_ipm_ver;
|
||||
unsigned short hdr_facility;
|
||||
unsigned int i;
|
||||
|
||||
/* First, a simple send... */
|
||||
status = libipm_msg_out_simple_send(
|
||||
g_t_out, TEST_MESSAGE_NO, "u", TEST_u_VALUE);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
/* Check the value */
|
||||
status = libipm_msg_in_parse( g_t_in, "u", &u);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
ck_assert_int_eq(u, TEST_u_VALUE);
|
||||
|
||||
/* Save existing header values */
|
||||
hdr_ipm_ver = get_header_field(g_t_out->out_s, HDR_IPM_VER);
|
||||
hdr_facility = get_header_field(g_t_out->out_s, HDR_FACILITY);
|
||||
|
||||
test_bad_header_value(HDR_IPM_VER, hdr_ipm_ver + 1);
|
||||
test_bad_header_value(HDR_FACILITY, hdr_facility - 1);
|
||||
test_bad_header_value(HDR_RESERVED, 0xff);
|
||||
test_bad_header_value(HDR_MSG_LEN, LIBIPM_MAX_MESSAGE_SIZE + 1);
|
||||
test_bad_header_value(HDR_MSG_LEN, 0xffff);
|
||||
for (i = 0 ; i < LIBIPM_HEADER_SIZE; ++i)
|
||||
{
|
||||
test_bad_header_value(HDR_MSG_LEN, i);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks message erase works as expected
|
||||
*/
|
||||
START_TEST(test_libipm_receive_msg_erase)
|
||||
{
|
||||
enum libipm_status status;
|
||||
int istatus;
|
||||
const char *username = "username";
|
||||
const char *password = "password";
|
||||
|
||||
/* Send a message containing sensitive information */
|
||||
status = libipm_msg_out_simple_send(g_t_out, TEST_MESSAGE_NO, "ss",
|
||||
username, password);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
libipm_set_flags(g_t_in, LIBIPM_E_MSG_IN_ERASE_AFTER_USE);
|
||||
|
||||
ck_assert_int_ne(does_stream_contain_string(g_t_in->in_s, password), 0);
|
||||
libipm_msg_in_reset(g_t_in);
|
||||
ck_assert_msg(does_stream_contain_string(g_t_in->in_s, password) == 0,
|
||||
"Auto buffer reset on input not working");
|
||||
|
||||
/* The flag should be reset automatically */
|
||||
/* Resend and re-catch the message */
|
||||
istatus = trans_force_write(g_t_out);
|
||||
ck_assert_int_eq(istatus, 0);
|
||||
check_for_incoming_message(TEST_MESSAGE_NO);
|
||||
|
||||
ck_assert_int_ne(does_stream_contain_string(g_t_in->in_s, password), 0);
|
||||
libipm_msg_in_reset(g_t_in);
|
||||
ck_assert_msg(does_stream_contain_string(g_t_in->in_s, password) != 0,
|
||||
"LIBIPM_E_MSG_IN_ERASE_AFTER_USE not automatically cleared");
|
||||
}
|
||||
END_TEST
|
||||
/***************************************************************************//**
|
||||
* Exercises codepaths that shouldn't be called (programming errors)
|
||||
*/
|
||||
START_TEST(test_libipm_receive_programming_errors)
|
||||
{
|
||||
enum libipm_status status;
|
||||
int available;
|
||||
int32_t dummy;
|
||||
|
||||
status = libipm_msg_in_wait_available(g_t_vanilla);
|
||||
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
|
||||
|
||||
status = libipm_msg_in_check_available(g_t_vanilla, &available);
|
||||
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
|
||||
|
||||
status = libipm_msg_in_parse(g_t_vanilla, "i", &dummy);
|
||||
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
|
||||
|
||||
libipm_msg_in_reset(g_t_vanilla); /* No status to check */
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
Suite *
|
||||
make_suite_test_libipm_recv_calls(void)
|
||||
{
|
||||
Suite *s;
|
||||
TCase *tc;
|
||||
|
||||
s = suite_create("libipm_recv");
|
||||
|
||||
tc = tcase_create("libipm_recv");
|
||||
suite_add_tcase(s, tc);
|
||||
tcase_add_test(tc, test_libipm_send_recv_all_test);
|
||||
tcase_add_test(tc, test_libipm_receive_y_type);
|
||||
tcase_add_test(tc, test_libipm_receive_b_type);
|
||||
tcase_add_test(tc, test_libipm_receive_n_type);
|
||||
tcase_add_test(tc, test_libipm_receive_q_type);
|
||||
tcase_add_test(tc, test_libipm_receive_i_type);
|
||||
tcase_add_test(tc, test_libipm_receive_u_type);
|
||||
tcase_add_test(tc, test_libipm_receive_x_type);
|
||||
tcase_add_test(tc, test_libipm_receive_t_type);
|
||||
tcase_add_test(tc, test_libipm_receive_s_type);
|
||||
tcase_add_test(tc, test_libipm_receive_B_type);
|
||||
tcase_add_test(tc, test_libipm_receive_no_type);
|
||||
tcase_add_test(tc, test_libipm_receive_unexpected_type);
|
||||
tcase_add_test(tc, test_libipm_receive_unsupported_type);
|
||||
tcase_add_test(tc, test_libipm_receive_unimplemented_type);
|
||||
tcase_add_test(tc, test_libipm_receive_bad_header);
|
||||
tcase_add_test(tc, test_libipm_receive_msg_erase);
|
||||
tcase_add_test(tc, test_libipm_receive_programming_errors);
|
||||
|
||||
return s;
|
||||
}
|
|
@ -0,0 +1,506 @@
|
|||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "libipm.h"
|
||||
#include "os_calls.h"
|
||||
#include "string_calls.h"
|
||||
#include "trans.h"
|
||||
|
||||
#include "test_libipm.h"
|
||||
|
||||
/* Random(ish) values for test_libipm_append_all_test */
|
||||
#define ALL_TEST_y_VALUE 45
|
||||
#define ALL_TEST_b_VALUE 0
|
||||
#define ALL_TEST_n_VALUE -14
|
||||
#define ALL_TEST_q_VALUE 327
|
||||
#define ALL_TEST_i_VALUE -100000
|
||||
#define ALL_TEST_u_VALUE 100000
|
||||
#define ALL_TEST_x_VALUE -4000000000L
|
||||
#define ALL_TEST_t_VALUE 8000000000L
|
||||
#define ALL_TEST_s_VALUE \
|
||||
'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0'
|
||||
#define ALL_TEST_B_VALUE 'a', 'z', 'A', 'Z', '0', '9', '#'
|
||||
|
||||
/* This macro generates two unsigned char values, separated by a comma,
|
||||
* representing a 2's complement little-endian 16-bit integer */
|
||||
#define BITS16_LE(x) ((x) & 0xff), (((unsigned int)(x) >> 8) & 0xff)
|
||||
|
||||
/* This macro generates four unsigned char values, separated by a comma,
|
||||
* representing a 2's complement little-endian 32-bit integer */
|
||||
#define BITS32_LE(x) BITS16_LE((x) & 0xffff), \
|
||||
BITS16_LE(((unsigned int)(x) >> 16) & 0xffff)
|
||||
|
||||
/* This macro generates eight unsigned char values, separated by a comma,
|
||||
* representing a 2's complement little-endian 64-bit integer */
|
||||
#define BITS64_LE(x) BITS32_LE((uint64_t)(x) & 0xffffffff), \
|
||||
BITS32_LE(((uint64_t)(x) >> 32) & 0xffffffff)
|
||||
|
||||
/* Expected buffer contents for test_libipm_append_all_test */
|
||||
static const unsigned char all_test_expected_buff[] =
|
||||
{
|
||||
BITS16_LE(LIBIPM_VERSION),
|
||||
BITS16_LE(73), /* Header : message length */
|
||||
BITS16_LE(LIBIPM_FAC_TEST),
|
||||
BITS16_LE(TEST_MESSAGE_NO),
|
||||
BITS32_LE(0),
|
||||
/* ------------------- */
|
||||
'y', ALL_TEST_y_VALUE,
|
||||
'b', ALL_TEST_b_VALUE,
|
||||
'n', BITS16_LE(ALL_TEST_n_VALUE),
|
||||
'q', BITS16_LE(ALL_TEST_q_VALUE),
|
||||
'i', BITS32_LE(ALL_TEST_i_VALUE),
|
||||
'u', BITS32_LE(ALL_TEST_u_VALUE),
|
||||
'x', BITS64_LE(ALL_TEST_x_VALUE),
|
||||
't', BITS64_LE(ALL_TEST_t_VALUE),
|
||||
/* String + terminator */
|
||||
's', ALL_TEST_s_VALUE,
|
||||
/* Fixed size block */
|
||||
'B', BITS16_LE(7) /* length */, ALL_TEST_B_VALUE
|
||||
};
|
||||
|
||||
/* Type used to map small test values (i.e. simple types that fit in an int)
|
||||
* to expected status codes if we try to output them for a given tyoe */
|
||||
struct int_test_value
|
||||
{
|
||||
int value;
|
||||
enum libipm_status expected_status;
|
||||
};
|
||||
|
||||
/***************************************************************************//**
|
||||
* Compares the data in a stream against an expected data block
|
||||
*
|
||||
* @param s Stream to check
|
||||
* @param expdata Expected data
|
||||
* @aram explen Expected data len
|
||||
*/
|
||||
static void
|
||||
check_stream_data_eq(const struct stream *s,
|
||||
const unsigned char *expected_data,
|
||||
unsigned int expected_len)
|
||||
{
|
||||
check_binary_data_eq((unsigned char *)s->data,
|
||||
(unsigned int)(s->end - s->data),
|
||||
expected_data,
|
||||
expected_len);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Value checks for small types (i.e. those that fit in an 'int' */
|
||||
static void
|
||||
test_small_type_values(char typechar,
|
||||
const struct int_test_value v[], unsigned int count)
|
||||
{
|
||||
unsigned int i;
|
||||
enum libipm_status status;
|
||||
char format[] = { typechar, '\0'};
|
||||
|
||||
for (i = 0 ; i < count; ++i)
|
||||
{
|
||||
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO,
|
||||
format, v[i].value);
|
||||
if (status != v[i].expected_status)
|
||||
{
|
||||
ck_abort_msg("Test value %d. Expected status %d, got %d",
|
||||
v[i].value, v[i].expected_status, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks we can add a simple type right at the end of a buffer, but that
|
||||
* a buffer overflow is also detected if there's not enough space.
|
||||
*/
|
||||
static void
|
||||
test_append_at_end_of_message(char typechar, unsigned int wire_size)
|
||||
{
|
||||
char padding[LIBIPM_MAX_PAYLOAD_SIZE] = {0};
|
||||
struct libipm_fsb desc;
|
||||
enum libipm_status status;
|
||||
const char format[] = {'B', typechar, '\0'};
|
||||
|
||||
/* Construct a descriptor for a binary object that fills most of
|
||||
* the output buffer, leaving just enough space for our type at the end.
|
||||
* Three bytes are needed for the binary descriptor overhead */
|
||||
desc.data = padding;
|
||||
desc.datalen = LIBIPM_MAX_PAYLOAD_SIZE - 3 - wire_size;
|
||||
|
||||
/* Check we're OK at the end of the buffer... */
|
||||
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, format, &desc, 0);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
/* ..but if the value would overflow the end of the packet it's an error */
|
||||
++desc.datalen;
|
||||
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, format, &desc, 0);
|
||||
ck_assert_int_eq(status, E_LI_BUFFER_OVERFLOW);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Appends all data types to a transport, and checks the binary data in
|
||||
* the output stream is as expected */
|
||||
START_TEST(test_libipm_append_all_test)
|
||||
{
|
||||
ck_assert_ptr_ne(g_t_out, NULL);
|
||||
|
||||
static char string[] = { ALL_TEST_s_VALUE };
|
||||
static char binary[] = { ALL_TEST_B_VALUE };
|
||||
struct libipm_fsb binary_desc = { (void *)binary, sizeof(binary) };
|
||||
enum libipm_status status;
|
||||
|
||||
status = libipm_msg_out_init(
|
||||
g_t_out, TEST_MESSAGE_NO,
|
||||
"ybnqiuxtsB",
|
||||
ALL_TEST_y_VALUE,
|
||||
ALL_TEST_b_VALUE,
|
||||
ALL_TEST_n_VALUE,
|
||||
ALL_TEST_q_VALUE,
|
||||
ALL_TEST_i_VALUE,
|
||||
ALL_TEST_u_VALUE,
|
||||
ALL_TEST_x_VALUE,
|
||||
ALL_TEST_t_VALUE,
|
||||
string,
|
||||
&binary_desc);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
libipm_msg_out_mark_end(g_t_out);
|
||||
|
||||
check_stream_data_eq(
|
||||
g_t_out->out_s,
|
||||
all_test_expected_buff, sizeof(all_test_expected_buff));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various send errors for 'y'
|
||||
*/
|
||||
START_TEST(test_libipm_send_y_type)
|
||||
{
|
||||
static const struct int_test_value test_values[] =
|
||||
{
|
||||
{0, E_LI_SUCCESS},
|
||||
{255, E_LI_SUCCESS},
|
||||
{-1, E_LI_BAD_VALUE},
|
||||
{256, E_LI_BAD_VALUE},
|
||||
{63336, E_LI_BAD_VALUE},
|
||||
{2147483647, E_LI_BAD_VALUE}
|
||||
};
|
||||
|
||||
test_small_type_values('y', test_values,
|
||||
sizeof(test_values) / sizeof(test_values[0]));
|
||||
|
||||
test_append_at_end_of_message('y', 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various send errors for 'b'
|
||||
*/
|
||||
START_TEST(test_libipm_send_b_type)
|
||||
{
|
||||
static const struct int_test_value test_values[] =
|
||||
{
|
||||
{0, E_LI_SUCCESS},
|
||||
{1, E_LI_SUCCESS},
|
||||
{2, E_LI_BAD_VALUE},
|
||||
{-1, E_LI_BAD_VALUE},
|
||||
{256, E_LI_BAD_VALUE}
|
||||
};
|
||||
|
||||
test_small_type_values('b', test_values,
|
||||
sizeof(test_values) / sizeof(test_values[0]));
|
||||
|
||||
test_append_at_end_of_message('b', 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various send errors for 'n'
|
||||
*/
|
||||
START_TEST(test_libipm_send_n_type)
|
||||
{
|
||||
static const struct int_test_value test_values[] =
|
||||
{
|
||||
{-32768, E_LI_SUCCESS},
|
||||
{32767, E_LI_SUCCESS},
|
||||
{-32769, E_LI_BAD_VALUE},
|
||||
{32768, E_LI_BAD_VALUE},
|
||||
{2147483647, E_LI_BAD_VALUE}
|
||||
};
|
||||
|
||||
test_small_type_values('n', test_values,
|
||||
sizeof(test_values) / sizeof(test_values[0]));
|
||||
|
||||
test_append_at_end_of_message('n', 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various send errors for 'q'
|
||||
*/
|
||||
START_TEST(test_libipm_send_q_type)
|
||||
{
|
||||
static const struct int_test_value test_values[] =
|
||||
{
|
||||
{0, E_LI_SUCCESS},
|
||||
{65535, E_LI_SUCCESS},
|
||||
{-1, E_LI_BAD_VALUE},
|
||||
{65536, E_LI_BAD_VALUE},
|
||||
{2147483647, E_LI_BAD_VALUE}
|
||||
};
|
||||
|
||||
test_small_type_values('q', test_values,
|
||||
sizeof(test_values) / sizeof(test_values[0]));
|
||||
|
||||
test_append_at_end_of_message('q', 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various send errors for 'i'
|
||||
*/
|
||||
START_TEST(test_libipm_send_i_type)
|
||||
{
|
||||
#if SIZEOF_INT > 4
|
||||
static const struct int_test_value test_values[] =
|
||||
{
|
||||
{-2147483648, E_LI_SUCCESS},
|
||||
{2147483647, E_LI_SUCCESS},
|
||||
{-2147483649, E_LI_BAD_VALUE},
|
||||
{2147483648, E_LI_BAD_VALUE},
|
||||
};
|
||||
|
||||
test_small_type_values('i', test_values,
|
||||
sizeof(test_values) / sizeof(test_values[0]));
|
||||
#endif
|
||||
test_append_at_end_of_message('i', 5);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various send errors for 'u'
|
||||
*/
|
||||
START_TEST(test_libipm_send_u_type)
|
||||
{
|
||||
#if SIZEOF_INT > 4
|
||||
static const struct int_test_value test_values[] =
|
||||
{
|
||||
{0, E_LI_SUCCESS},
|
||||
{4294967296, E_LI_SUCCESS},
|
||||
{-1, E_LI_BAD_VALUE},
|
||||
{4294967297, E_LI_BAD_VALUE},
|
||||
};
|
||||
|
||||
test_small_type_values('u', test_values,
|
||||
sizeof(test_values) / sizeof(test_values[0]));
|
||||
#endif
|
||||
test_append_at_end_of_message('u', 5);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various send errors for 'x'
|
||||
*/
|
||||
START_TEST(test_libipm_send_x_type)
|
||||
{
|
||||
test_append_at_end_of_message('x', 9);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various send errors for 't'
|
||||
*/
|
||||
START_TEST(test_libipm_send_t_type)
|
||||
{
|
||||
test_append_at_end_of_message('t', 9);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various send errors for 's'
|
||||
*/
|
||||
START_TEST(test_libipm_send_s_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
|
||||
/* The maximum string length would be LIBIPM_MAX_PAYLOAD_SIZE-2, as we
|
||||
* need one char for the 's' type marker, and another for the string
|
||||
* terminator */
|
||||
|
||||
/* Construct a string one character too long to fit in the buffer */
|
||||
char str[LIBIPM_MAX_PAYLOAD_SIZE];
|
||||
|
||||
g_memset(str, 'A', sizeof(str));
|
||||
str[sizeof(str) - 1] = '\0';
|
||||
|
||||
/* A write should overflow... */
|
||||
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "s", str);
|
||||
ck_assert_int_eq(status, E_LI_BUFFER_OVERFLOW);
|
||||
|
||||
/* .. but a string one character shorter should be OK */
|
||||
str[sizeof(str) - 2] = '\0';
|
||||
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "s", str);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
/* Check passing a NULL string doesn't crash the program */
|
||||
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "s", NULL);
|
||||
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks various send errors for 'B'
|
||||
*/
|
||||
START_TEST(test_libipm_send_B_type)
|
||||
{
|
||||
enum libipm_status status;
|
||||
char bin[LIBIPM_MAX_PAYLOAD_SIZE] = {0};
|
||||
struct libipm_fsb desc;
|
||||
|
||||
/* The maximum binary block length would be LIBIPM_MAX_PAYLOAD_SIZE - 3,
|
||||
* as we need one char for the 'B' type marker, and two for the length
|
||||
*
|
||||
* Construct a descriptor for a binary object that completely fills
|
||||
* the output buffer */
|
||||
desc.data = bin;
|
||||
desc.datalen = LIBIPM_MAX_PAYLOAD_SIZE - 3;
|
||||
|
||||
/* Check it fits in the buffer... */
|
||||
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", &desc);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
/* ..but one byte bigger, and it won't fit */
|
||||
++desc.datalen;
|
||||
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", &desc);
|
||||
ck_assert_int_eq(status, E_LI_BUFFER_OVERFLOW);
|
||||
--desc.datalen;
|
||||
|
||||
/* Check NULL pointers don't crash the library */
|
||||
desc.data = NULL;
|
||||
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", &desc);
|
||||
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
|
||||
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", NULL);
|
||||
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks send errors for unsupported and unimplemented types
|
||||
*/
|
||||
START_TEST(test_libipm_send_bad_types)
|
||||
{
|
||||
enum libipm_status status;
|
||||
enum libipm_status expected_status;
|
||||
char format[2] = {0};
|
||||
char c;
|
||||
|
||||
for (c = 0x1; c < 0x7f; ++c)
|
||||
{
|
||||
if (!isprint(c))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g_strchr(g_supported_types, c) == NULL)
|
||||
{
|
||||
expected_status = E_LI_UNSUPPORTED_TYPE;
|
||||
}
|
||||
else if (g_strchr(g_unimplemented_types, c) != NULL)
|
||||
{
|
||||
expected_status = E_LI_UNIMPLEMENTED_TYPE;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
format[0] = c;
|
||||
status = libipm_msg_out_init(g_t_out,
|
||||
TEST_MESSAGE_NO_STRING_NO,
|
||||
format, NULL);
|
||||
if (status != expected_status)
|
||||
{
|
||||
ck_abort_msg("Output char '%c'. Expected status %d, got %d",
|
||||
c, expected_status, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks message erase works as expected
|
||||
*
|
||||
* Also calls libipm_msg_out_append() which isn't exercised anywhere else
|
||||
*/
|
||||
START_TEST(test_libipm_send_msg_erase)
|
||||
{
|
||||
enum libipm_status status;
|
||||
const char *username = "username";
|
||||
const char *password = "password";
|
||||
|
||||
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, NULL);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
status = libipm_msg_out_append(g_t_out, "ss", username, password);
|
||||
ck_assert_int_eq(status, E_LI_SUCCESS);
|
||||
|
||||
ck_assert_int_ne(does_stream_contain_string(g_t_out->out_s, password), 0);
|
||||
libipm_msg_out_erase(g_t_out);
|
||||
ck_assert_int_eq(does_stream_contain_string(g_t_out->out_s, password), 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/***************************************************************************//**
|
||||
* Exercises codepaths that shouldn't be called (programming errors)
|
||||
*/
|
||||
START_TEST(test_libipm_send_programming_errors)
|
||||
{
|
||||
enum libipm_status status;
|
||||
|
||||
status = libipm_msg_out_init(g_t_vanilla, TEST_MESSAGE_NO, NULL);
|
||||
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
|
||||
|
||||
status = libipm_msg_out_append(g_t_vanilla, "i", 0);
|
||||
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
|
||||
|
||||
libipm_msg_out_mark_end(g_t_vanilla); /* No status to check */
|
||||
|
||||
status = libipm_msg_out_simple_send(g_t_vanilla, TEST_MESSAGE_NO, "i", 0);
|
||||
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
Suite *
|
||||
make_suite_test_libipm_send_calls(void)
|
||||
{
|
||||
Suite *s;
|
||||
TCase *tc;
|
||||
|
||||
s = suite_create("libipm_send");
|
||||
|
||||
tc = tcase_create("libipm_send");
|
||||
suite_add_tcase(s, tc);
|
||||
tcase_add_test(tc, test_libipm_append_all_test);
|
||||
tcase_add_test(tc, test_libipm_send_y_type);
|
||||
tcase_add_test(tc, test_libipm_send_b_type);
|
||||
tcase_add_test(tc, test_libipm_send_n_type);
|
||||
tcase_add_test(tc, test_libipm_send_q_type);
|
||||
tcase_add_test(tc, test_libipm_send_i_type);
|
||||
tcase_add_test(tc, test_libipm_send_u_type);
|
||||
tcase_add_test(tc, test_libipm_send_x_type);
|
||||
tcase_add_test(tc, test_libipm_send_t_type);
|
||||
tcase_add_test(tc, test_libipm_send_s_type);
|
||||
tcase_add_test(tc, test_libipm_send_B_type);
|
||||
tcase_add_test(tc, test_libipm_send_y_type);
|
||||
tcase_add_test(tc, test_libipm_send_bad_types);
|
||||
tcase_add_test(tc, test_libipm_send_msg_erase);
|
||||
tcase_add_test(tc, test_libipm_send_programming_errors);
|
||||
|
||||
return s;
|
||||
}
|
Loading…
Reference in New Issue