Add tests for libipm file descriptor calls

This commit is contained in:
matt335672 2023-01-09 20:54:53 +00:00
parent c9adb3a2a6
commit 7a190bf709
4 changed files with 186 additions and 7 deletions

View File

@ -11,6 +11,7 @@ enum
LIBIPM_VERSION = 2, LIBIPM_VERSION = 2,
LIBIPM_HEADER_SIZE = 12, LIBIPM_HEADER_SIZE = 12,
LIBIPM_MAX_MESSAGE_SIZE = 8192, LIBIPM_MAX_MESSAGE_SIZE = 8192,
LIBIPM_MAX_FD_PER_MSG = 8,
LIBIPM_MAX_PAYLOAD_SIZE = LIBIPM_MAX_MESSAGE_SIZE - LIBIPM_HEADER_SIZE LIBIPM_MAX_PAYLOAD_SIZE = LIBIPM_MAX_MESSAGE_SIZE - LIBIPM_HEADER_SIZE
}; };
@ -18,6 +19,7 @@ enum
extern struct trans *g_t_out; /* Channel for outputting libipm messages */ 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_in; /* Channel for inputting libipm messages */
extern struct trans *g_t_vanilla; /* Non-SCP channel */ extern struct trans *g_t_vanilla; /* Non-SCP channel */
extern int g_fd; /* An open file descriptor (/dev/zero) */
extern const char *g_supported_types; /* All recognised type codes */ extern const char *g_supported_types; /* All recognised type codes */
extern const char *g_unimplemented_types; /* recognised, unimplemented codes */ extern const char *g_unimplemented_types; /* recognised, unimplemented codes */
@ -42,6 +44,14 @@ check_binary_data_eq(const void *actual_data,
const void *expected_data, const void *expected_data,
unsigned int expected_len); unsigned int expected_len);
/**
* Check the file descriptor specified is working as /dev/zero
*
* If it isn't, an exception is raised using ck_* calls
*/
void
check_fd_is_dev_zero(int fd);
/** /**
* Looks for the specified string in the specified stream * Looks for the specified string in the specified stream
* @param s Stream to search * @param s Stream to search
@ -54,6 +64,11 @@ check_binary_data_eq(const void *actual_data,
int int
does_stream_contain_string(const struct stream *s, const char *str); does_stream_contain_string(const struct stream *s, const char *str);
/**
* Returns the number of open file descriptors in the process */
unsigned int
get_open_fd_count(void);
Suite *make_suite_test_libipm_send_calls(void); Suite *make_suite_test_libipm_send_calls(void);
Suite *make_suite_test_libipm_recv_calls(void); Suite *make_suite_test_libipm_recv_calls(void);

View File

@ -5,6 +5,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/resource.h>
#include <poll.h>
#include "log.h" #include "log.h"
#include "libipm.h" #include "libipm.h"
@ -17,9 +19,10 @@
struct trans *g_t_out = NULL; struct trans *g_t_out = NULL;
struct trans *g_t_in = NULL; struct trans *g_t_in = NULL;
struct trans *g_t_vanilla = NULL; struct trans *g_t_vanilla = NULL;
int g_fd = -1;
const char *g_supported_types = "ybnqiuxtsdhogB"; const char *g_supported_types = "ybnqiuxtsdhogB";
const char *g_unimplemented_types = "dhog"; const char *g_unimplemented_types = "dog";
/******************************************************************************/ /******************************************************************************/
static const char * static const char *
@ -37,6 +40,7 @@ suite_test_libipm_calls_start(void)
struct trans *t1 = NULL; struct trans *t1 = NULL;
struct trans *t2 = NULL; struct trans *t2 = NULL;
struct trans *t3 = NULL; struct trans *t3 = NULL;
int fd = -1;
int success = 0; int success = 0;
if ((t1 = trans_create(TRANS_MODE_UNIX, 128, 128)) == NULL) if ((t1 = trans_create(TRANS_MODE_UNIX, 128, 128)) == NULL)
@ -54,6 +58,11 @@ suite_test_libipm_calls_start(void)
const char *errstr = g_get_strerror(); const char *errstr = g_get_strerror();
LOG(LOG_LEVEL_ERROR, "Can't create test transport 3 [%s]", errstr); LOG(LOG_LEVEL_ERROR, "Can't create test transport 3 [%s]", errstr);
} }
else if ((fd = g_file_open("/dev/zero")) < 0)
{
const char *errstr = g_get_strerror();
LOG(LOG_LEVEL_ERROR, "Can't open /dev/zero [%s]", errstr);
}
else if ((istatus = g_sck_local_socketpair(sck)) < 0) else if ((istatus = g_sck_local_socketpair(sck)) < 0)
{ {
const char *errstr = g_get_strerror(); const char *errstr = g_get_strerror();
@ -89,12 +98,17 @@ suite_test_libipm_calls_start(void)
g_t_out = t1; g_t_out = t1;
g_t_in = t2; g_t_in = t2;
g_t_vanilla = t3; g_t_vanilla = t3;
g_fd = fd;
} }
else else
{ {
trans_delete(t1); trans_delete(t1);
trans_delete(t2); trans_delete(t2);
trans_delete(t3); trans_delete(t3);
if (fd >= 0)
{
g_file_close(fd);
}
} }
} }
@ -138,6 +152,20 @@ check_binary_data_eq(const void *actual_data,
} }
} }
/******************************************************************************/
void
check_fd_is_dev_zero(int fd)
{
char buff[1] = { '\001' };
int status;
status = g_file_read(fd, buff, sizeof(buff));
ck_assert_int_eq(status, 1);
ck_assert_int_eq(buff[0], '\0');
status = g_file_write(fd, buff, sizeof(buff));
ck_assert_int_eq(status, 1);
}
/******************************************************************************/ /******************************************************************************/
int int
@ -162,6 +190,51 @@ does_stream_contain_string(const struct stream *s, const char *str)
return 0; return 0;
} }
/******************************************************************************/
unsigned int
get_open_fd_count(void)
{
unsigned int i;
unsigned int rv;
// What's the max number of file descriptors?
struct rlimit nofile;
if (getrlimit(RLIMIT_NOFILE, &nofile) < 0)
{
const char *errstr = g_get_strerror();
ck_abort_msg("Can't create socketpair [%s]", errstr);
}
struct pollfd *fds =
(struct pollfd *)g_malloc(sizeof(struct pollfd) * nofile.rlim_cur, 0);
ck_assert_ptr_nonnull(fds);
for (i = 0 ; i < nofile.rlim_cur; ++i)
{
fds[i].fd = i;
fds[i].events = 0;
fds[i].revents = 0;
}
if (poll(fds, nofile.rlim_cur, 0) < 0)
{
const char *errstr = g_get_strerror();
ck_abort_msg("Can't poll fds [%s]", errstr);
}
rv = nofile.rlim_cur;
for (i = 0 ; i < nofile.rlim_cur; ++i)
{
if (fds[i].revents == POLLNVAL)
{
--rv;
}
}
g_free(fds);
return rv;
}
/******************************************************************************/ /******************************************************************************/
int main (void) int main (void)

View File

@ -245,13 +245,14 @@ START_TEST(test_libipm_send_recv_all_test)
int64_t x; int64_t x;
uint64_t t; uint64_t t;
char *s; char *s;
int h = -1;
char B[sizeof(bin_out)]; char B[sizeof(bin_out)];
char c; char c;
/* The message is small enough to fit in the socket buffer */ /* The message is small enough to fit in the socket buffer */
status = libipm_msg_out_simple_send( status = libipm_msg_out_simple_send(
g_t_out, TEST_MESSAGE_NO, g_t_out, TEST_MESSAGE_NO,
"ybnqiuxtsB", "ybnqiuxtshB",
TEST_y_VALUE, TEST_y_VALUE,
TEST_b_VALUE, TEST_b_VALUE,
TEST_n_VALUE, TEST_n_VALUE,
@ -261,6 +262,7 @@ START_TEST(test_libipm_send_recv_all_test)
TEST_x_VALUE, TEST_x_VALUE,
TEST_t_VALUE, TEST_t_VALUE,
TEST_s_VALUE, TEST_s_VALUE,
g_fd,
&binary_desc); &binary_desc);
ck_assert_int_eq(status, E_LI_SUCCESS); ck_assert_int_eq(status, E_LI_SUCCESS);
@ -273,8 +275,8 @@ START_TEST(test_libipm_send_recv_all_test)
status = libipm_msg_in_parse( status = libipm_msg_in_parse(
g_t_in, g_t_in,
"ybnqiuxtsB", "ybnqiuxtshB",
&y, &b, &n, &q, &i, &u, &x, &t, &s, &binary_desc); &y, &b, &n, &q, &i, &u, &x, &t, &s, &h, &binary_desc);
ck_assert_int_eq(status, E_LI_SUCCESS); ck_assert_int_eq(status, E_LI_SUCCESS);
ck_assert_int_eq(y, TEST_y_VALUE); ck_assert_int_eq(y, TEST_y_VALUE);
@ -287,6 +289,13 @@ START_TEST(test_libipm_send_recv_all_test)
ck_assert_int_eq(t, TEST_t_VALUE); ck_assert_int_eq(t, TEST_t_VALUE);
check_binary_data_eq(TEST_s_VALUE, sizeof(TEST_s_VALUE) - 1, check_binary_data_eq(TEST_s_VALUE, sizeof(TEST_s_VALUE) - 1,
s, g_strlen(s)); s, g_strlen(s));
/* The file descriptor should not be -1, neither should it be
* the value we sent. It should also point to /dev/zero */
ck_assert_int_ne(h, -1);
ck_assert_int_ne(h, g_fd);
check_fd_is_dev_zero(h);
g_file_close(h);
check_binary_data_eq(bin_out, sizeof(bin_out), B, sizeof(B)); check_binary_data_eq(bin_out, sizeof(bin_out), B, sizeof(B));
/* Check we're at the end of the message */ /* Check we're at the end of the message */
@ -540,8 +549,62 @@ START_TEST(test_libipm_receive_s_type)
} }
END_TEST END_TEST
/***************************************************************************//** /***************************************************************************//**
* Checks various receive errors for 's' * Checks various receive errors for 'h'
*/
START_TEST(test_libipm_receive_h_type)
{
enum libipm_status status;
int istatus;
unsigned int i;
int fd_count;
/* Get the number of open file descriptors */
int base_fd_count = get_open_fd_count();
ck_assert_int_gt(base_fd_count, 0);
/* Send the max number of copies of the /dev/zero
* file descriptor */
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, NULL);
ck_assert_int_eq(status, E_LI_SUCCESS);
for (i = 0 ; i < LIBIPM_MAX_FD_PER_MSG; ++i)
{
status = libipm_msg_out_append(g_t_out, "h", g_fd);
ck_assert_int_eq(status, E_LI_SUCCESS);
}
libipm_msg_out_mark_end(g_t_out);
istatus = trans_force_write(g_t_out);
ck_assert_int_eq(istatus, 0);
check_for_incoming_message(TEST_MESSAGE_NO);
/* Check the number of file descriptors has gone up as expected */
fd_count = get_open_fd_count();
ck_assert_int_eq(fd_count, base_fd_count + LIBIPM_MAX_FD_PER_MSG);
/* Check half the descriptors work */
for (i = 0 ; i < LIBIPM_MAX_FD_PER_MSG / 2; ++i)
{
int h = -1;
status = libipm_msg_in_parse(g_t_in, "h", &h);
ck_assert_int_eq(status, E_LI_SUCCESS);
check_fd_is_dev_zero(h);
g_file_close(h);
}
/* Close the message without reading the other descriptors */
libipm_msg_in_reset(g_t_in);
/* Check all the file descriptors we received have been closed */
fd_count = get_open_fd_count();
ck_assert_int_eq(fd_count, base_fd_count);
}
END_TEST
/***************************************************************************//**
* Checks various receive errors for 'B'
*/ */
START_TEST(test_libipm_receive_B_type) START_TEST(test_libipm_receive_B_type)
{ {
@ -844,6 +907,7 @@ make_suite_test_libipm_recv_calls(void)
tcase_add_test(tc, test_libipm_receive_x_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_t_type);
tcase_add_test(tc, test_libipm_receive_s_type); tcase_add_test(tc, test_libipm_receive_s_type);
tcase_add_test(tc, test_libipm_receive_h_type);
tcase_add_test(tc, test_libipm_receive_B_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_no_type);
tcase_add_test(tc, test_libipm_receive_unexpected_type); tcase_add_test(tc, test_libipm_receive_unexpected_type);

View File

@ -44,7 +44,7 @@
static const unsigned char all_test_expected_buff[] = static const unsigned char all_test_expected_buff[] =
{ {
BITS16_LE(LIBIPM_VERSION), BITS16_LE(LIBIPM_VERSION),
BITS16_LE(73), /* Header : message length */ BITS16_LE(74), /* Header : message length */
BITS16_LE(LIBIPM_FAC_TEST), BITS16_LE(LIBIPM_FAC_TEST),
BITS16_LE(TEST_MESSAGE_NO), BITS16_LE(TEST_MESSAGE_NO),
BITS32_LE(0), BITS32_LE(0),
@ -59,6 +59,7 @@ static const unsigned char all_test_expected_buff[] =
't', BITS64_LE(ALL_TEST_t_VALUE), 't', BITS64_LE(ALL_TEST_t_VALUE),
/* String + terminator */ /* String + terminator */
's', ALL_TEST_s_VALUE, 's', ALL_TEST_s_VALUE,
'h', /* No buffer value is needed for 'h' */
/* Fixed size block */ /* Fixed size block */
'B', BITS16_LE(7) /* length */, ALL_TEST_B_VALUE 'B', BITS16_LE(7) /* length */, ALL_TEST_B_VALUE
}; };
@ -154,7 +155,7 @@ START_TEST(test_libipm_append_all_test)
status = libipm_msg_out_init( status = libipm_msg_out_init(
g_t_out, TEST_MESSAGE_NO, g_t_out, TEST_MESSAGE_NO,
"ybnqiuxtsB", "ybnqiuxtshB",
ALL_TEST_y_VALUE, ALL_TEST_y_VALUE,
ALL_TEST_b_VALUE, ALL_TEST_b_VALUE,
ALL_TEST_n_VALUE, ALL_TEST_n_VALUE,
@ -164,6 +165,7 @@ START_TEST(test_libipm_append_all_test)
ALL_TEST_x_VALUE, ALL_TEST_x_VALUE,
ALL_TEST_t_VALUE, ALL_TEST_t_VALUE,
string, string,
g_fd,
&binary_desc); &binary_desc);
ck_assert_int_eq(status, E_LI_SUCCESS); ck_assert_int_eq(status, E_LI_SUCCESS);
@ -352,6 +354,30 @@ START_TEST(test_libipm_send_s_type)
} }
END_TEST END_TEST
/***************************************************************************//**
* Checks various send errors for 'h'
*/
START_TEST(test_libipm_send_h_type)
{
enum libipm_status status;
unsigned int i;
test_append_at_end_of_message('h', 1);
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, NULL);
ck_assert_int_eq(status, E_LI_SUCCESS);
for (i = 0 ; i < LIBIPM_MAX_FD_PER_MSG; ++i)
{
status = libipm_msg_out_append(g_t_out, "h", g_fd);
ck_assert_int_eq(status, E_LI_SUCCESS);
}
status = libipm_msg_out_append(g_t_out, "h", 1);
ck_assert_int_eq(status, E_LI_TOO_MANY_FDS);
}
END_TEST
/***************************************************************************//** /***************************************************************************//**
* Checks various send errors for 'B' * Checks various send errors for 'B'
*/ */
@ -496,6 +522,7 @@ make_suite_test_libipm_send_calls(void)
tcase_add_test(tc, test_libipm_send_x_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_t_type);
tcase_add_test(tc, test_libipm_send_s_type); tcase_add_test(tc, test_libipm_send_s_type);
tcase_add_test(tc, test_libipm_send_h_type);
tcase_add_test(tc, test_libipm_send_B_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_y_type);
tcase_add_test(tc, test_libipm_send_bad_types); tcase_add_test(tc, test_libipm_send_bad_types);