Moved unit tests into tests/unit

This commit is contained in:
Alex Young
2012-07-03 10:53:08 +01:00
parent e817129c47
commit c0c9c6f076
16 changed files with 6 additions and 3 deletions

229
tests/unit/check_acl.c Normal file
View File

@@ -0,0 +1,229 @@
#include <check.h>
#include <stdio.h>
#include "acl.h"
#include "util.h"
START_TEST( test_null_acl )
{
struct acl *acl = acl_create( 0,NULL, 0 );
fail_if( NULL == acl, "No acl alloced." );
fail_unless( 0 == acl->len, "Incorrect length" );
}
END_TEST
START_TEST( test_parses_single_line )
{
char *lines[] = {"127.0.0.1"};
struct acl * acl = acl_create( 1, lines, 0 );
fail_unless( 1 == acl->len, "Incorrect length." );
fail_if( NULL == acl->entries, "No entries present." );
}
END_TEST
START_TEST( test_parses_multiple_lines )
{
char *lines[] = {"127.0.0.1", "::1"};
struct acl * acl = acl_create( 2, lines, 0 );
union mysockaddr e0, e1;
parse_ip_to_sockaddr( &e0.generic, lines[0] );
parse_ip_to_sockaddr( &e1.generic, lines[1] );
fail_unless( acl->len == 2, "Multiple lines not parsed" );
struct ip_and_mask *entry;
entry = &(*acl->entries)[0];
fail_unless(entry->ip.family == e0.family, "entry 0 has wrong family!");
entry = &(*acl->entries)[1];
fail_unless(entry->ip.family == e1.family, "entry 1 has wrong family!");
}
END_TEST
START_TEST( test_destroy_doesnt_crash )
{
char *lines[] = {"127.0.0.1"};
struct acl * acl = acl_create( 1, lines, 0 );
acl_destroy( acl );
}
END_TEST
START_TEST( test_includes_single_address )
{
char *lines[] = {"127.0.0.1"};
struct acl * acl = acl_create( 1, lines, 0 );
union mysockaddr x;
parse_ip_to_sockaddr( &x.generic, "127.0.0.1" );
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
}
END_TEST
START_TEST( test_includes_single_address_when_netmask_specified_ipv4 )
{
char *lines[] = {"127.0.0.1/24"};
struct acl * acl = acl_create( 1, lines, 0 );
union mysockaddr x;
parse_ip_to_sockaddr( &x.generic, "127.0.0.0" );
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
parse_ip_to_sockaddr( &x.generic, "127.0.0.1" );
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
parse_ip_to_sockaddr( &x.generic, "127.0.0.255" );
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
}
END_TEST
START_TEST( test_includes_single_address_when_netmask_specified_ipv6 )
{
char *lines[] = {"fe80::/10"};
struct acl * acl = acl_create( 1, lines, 0 );
union mysockaddr x;
parse_ip_to_sockaddr( &x.generic, "fe80::1" );
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
parse_ip_to_sockaddr( &x.generic, "fe80::2" );
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
parse_ip_to_sockaddr( &x.generic, "fe80:ffff:ffff::ffff" );
fail_unless( acl_includes( acl, &x ), "Included address wasn't covered" );
}
END_TEST
START_TEST( test_includes_single_address_when_multiple_entries_exist )
{
char *lines[] = {"127.0.0.1", "::1"};
struct acl * acl = acl_create( 2, lines, 0 );
union mysockaddr e0;
union mysockaddr e1;
parse_ip_to_sockaddr( &e0.generic, "127.0.0.1" );
parse_ip_to_sockaddr( &e1.generic, "::1" );
fail_unless( acl_includes( acl, &e0 ), "Included address 0 wasn't covered" );
fail_unless( acl_includes( acl, &e1 ), "Included address 1 wasn't covered" );
}
END_TEST
START_TEST( test_doesnt_include_other_address )
{
char *lines[] = {"127.0.0.1"};
struct acl * acl = acl_create( 1, lines, 0 );
union mysockaddr x;
parse_ip_to_sockaddr( &x.generic, "127.0.0.2" );
fail_if( acl_includes( acl, &x ), "Excluded address was covered." );
}
END_TEST
START_TEST( test_doesnt_include_other_address_when_netmask_specified )
{
char *lines[] = {"127.0.0.1/32"};
struct acl * acl = acl_create( 1, lines, 0 );
union mysockaddr x;
parse_ip_to_sockaddr( &x.generic, "127.0.0.2" );
fail_if( acl_includes( acl, &x ), "Excluded address was covered." );
}
END_TEST
START_TEST( test_doesnt_include_other_address_when_multiple_entries_exist )
{
char *lines[] = {"127.0.0.1", "::1"};
struct acl * acl = acl_create( 2, lines, 0 );
union mysockaddr e0;
union mysockaddr e1;
parse_ip_to_sockaddr( &e0.generic, "127.0.0.2" );
parse_ip_to_sockaddr( &e1.generic, "::2" );
fail_if( acl_includes( acl, &e0 ), "Excluded address 0 was covered." );
fail_if( acl_includes( acl, &e1 ), "Excluded address 1 was covered." );
}
END_TEST
START_TEST( test_default_deny_rejects )
{
struct acl * acl = acl_create( 0, NULL, 1 );
union mysockaddr x;
parse_ip_to_sockaddr( &x.generic, "127.0.0.1" );
fail_if( acl_includes( acl, &x ), "Default deny accepted." );
}
END_TEST
START_TEST( test_default_accept_rejects )
{
struct acl * acl = acl_create( 0, NULL, 0 );
union mysockaddr x;
parse_ip_to_sockaddr( &x.generic, "127.0.0.1" );
fail_unless( acl_includes( acl, &x ), "Default accept rejected." );
}
END_TEST
Suite* acl_suite(void)
{
Suite *s = suite_create("acl");
TCase *tc_create = tcase_create("create");
TCase *tc_includes = tcase_create("includes");
TCase *tc_destroy = tcase_create("destroy");
tcase_add_test(tc_create, test_null_acl);
tcase_add_test(tc_create, test_parses_single_line);
tcase_add_test(tc_includes, test_parses_multiple_lines);
tcase_add_test(tc_includes, test_includes_single_address);
tcase_add_test(tc_includes, test_includes_single_address_when_netmask_specified_ipv4);
tcase_add_test(tc_includes, test_includes_single_address_when_netmask_specified_ipv6);
tcase_add_test(tc_includes, test_includes_single_address_when_multiple_entries_exist);
tcase_add_test(tc_includes, test_doesnt_include_other_address);
tcase_add_test(tc_includes, test_doesnt_include_other_address_when_netmask_specified);
tcase_add_test(tc_includes, test_doesnt_include_other_address_when_multiple_entries_exist);
tcase_add_test(tc_includes, test_default_deny_rejects);
tcase_add_test(tc_includes, test_default_accept_rejects);
tcase_add_test(tc_destroy, test_destroy_doesnt_crash);
suite_add_tcase(s, tc_create);
suite_add_tcase(s, tc_includes);
suite_add_tcase(s, tc_destroy);
return s;
}
int main(void)
{
#ifdef DEBUG
log_level = 0;
#else
log_level = 2;
#endif
int number_failed;
Suite *s = acl_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
log_level = 0;
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

204
tests/unit/check_bitset.c Normal file
View File

@@ -0,0 +1,204 @@
#include <check.h>
#include "bitset.h"
START_TEST(test_bit_set)
{
uint64_t num = 0;
char *bits = (char*) &num;
#define TEST_BIT_SET(bit, newvalue) \
bit_set(bits, (bit)); \
fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue));
TEST_BIT_SET(0, 1);
TEST_BIT_SET(1, 3);
TEST_BIT_SET(2, 7);
TEST_BIT_SET(7, 0x87);
TEST_BIT_SET(63, 0x8000000000000087);
}
END_TEST
START_TEST(test_bit_clear)
{
uint64_t num = 0xffffffffffffffff;
char *bits = (char*) &num;
#define TEST_BIT_CLEAR(bit, newvalue) \
bit_clear(bits, (bit)); \
fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue));
TEST_BIT_CLEAR(0, 0xfffffffffffffffe);
TEST_BIT_CLEAR(1, 0xfffffffffffffffc);
TEST_BIT_CLEAR(2, 0xfffffffffffffff8);
TEST_BIT_CLEAR(7, 0xffffffffffffff78);
TEST_BIT_CLEAR(63,0x7fffffffffffff78);
}
END_TEST
START_TEST(test_bit_tests)
{
uint64_t num = 0x5555555555555555;
char *bits = (char*) &num;
fail_unless(bit_has_value(bits, 0, 1), "bit_has_value malfunction");
fail_unless(bit_has_value(bits, 1, 0), "bit_has_value malfunction");
fail_unless(bit_has_value(bits, 63, 0), "bit_has_value malfunction");
fail_unless(bit_is_set(bits, 0), "bit_is_set malfunction");
fail_unless(bit_is_clear(bits, 1), "bit_is_clear malfunction");
fail_unless(bit_is_set(bits, 62), "bit_is_set malfunction");
fail_unless(bit_is_clear(bits, 63), "bit_is_clear malfunction");
}
END_TEST
START_TEST(test_bit_ranges)
{
char buffer[4160];
uint64_t *longs = (unsigned long*) buffer;
uint64_t i;
memset(buffer, 0, 4160);
for (i=0; i<64; i++) {
bit_set_range(buffer, i*64, i);
fail_unless(
longs[i] == (1UL<<i)-1,
"longs[%ld] = %lx SHOULD BE %lx",
i, longs[i], (1L<<i)-1
);
fail_unless(longs[i+1] == 0, "bit_set_range overshot at i=%d", i);
}
for (i=0; i<64; i++) {
bit_clear_range(buffer, i*64, i);
fail_unless(longs[i] == 0, "bit_clear_range didn't work at i=%d", i);
}
}
END_TEST
START_TEST(test_bit_runs)
{
char buffer[256];
int i, ptr=0, runs[] = {
56,97,22,12,83,1,45,80,85,51,64,40,63,67,75,64,94,81,79,62
};
memset(buffer,0,256);
for (i=0; i < 20; i += 2) {
ptr += runs[i];
bit_set_range(buffer, ptr, runs[i+1]);
ptr += runs[i+1];
}
ptr = 0;
for (i=0; i < 20; i += 1) {
int run = bit_run_count(buffer, ptr, 2048-ptr);
fail_unless(
run == runs[i],
"run %d should have been %d, was %d",
i, runs[i], run
);
ptr += runs[i];
}
}
END_TEST
START_TEST(test_bitset)
{
struct bitset_mapping* map;
uint64_t *num;
map = bitset_alloc(6400, 100);
num = (uint64_t*) map->bits;
bitset_set_range(map,0,50);
ck_assert_int_eq(1, *num);
bitset_set_range(map,99,1);
ck_assert_int_eq(1, *num);
bitset_set_range(map,100,1);
ck_assert_int_eq(3, *num);
bitset_set_range(map,0,800);
ck_assert_int_eq(255, *num);
bitset_set_range(map,1499,2);
ck_assert_int_eq(0xc0ff, *num);
bitset_clear_range(map,1499,2);
ck_assert_int_eq(255, *num);
*num = 0;
bitset_set_range(map, 1499, 2);
bitset_clear_range(map, 1300, 200);
ck_assert_int_eq(0x8000, *num);
*num = 0;
bitset_set_range(map, 0, 6400);
ck_assert_int_eq(0xffffffffffffffff, *num);
bitset_clear_range(map, 3200, 400);
ck_assert_int_eq(0xfffffff0ffffffff, *num);
}
END_TEST
START_TEST( test_bitset_set )
{
struct bitset_mapping* map;
uint64_t *num;
map = bitset_alloc(64, 1);
num = (uint64_t*) map->bits;
ck_assert_int_eq( 0x0000000000000000, *num );
bitset_set( map );
ck_assert_int_eq( 0xffffffffffffffff, *num );
}
END_TEST
START_TEST( test_bitset_clear )
{
struct bitset_mapping* map;
uint64_t *num;
map = bitset_alloc(64, 1);
num = (uint64_t*) map->bits;
ck_assert_int_eq( 0x0000000000000000, *num );
bitset_set( map );
bitset_clear( map );
ck_assert_int_eq( 0x0000000000000000, *num );
}
END_TEST
Suite* bitset_suite(void)
{
Suite *s = suite_create("bitset");
TCase *tc_bit = tcase_create("bit");
TCase *tc_bitset = tcase_create("bitset");
tcase_add_test(tc_bit, test_bit_set);
tcase_add_test(tc_bit, test_bit_clear);
tcase_add_test(tc_bit, test_bit_tests);
tcase_add_test(tc_bit, test_bit_ranges);
tcase_add_test(tc_bit, test_bit_runs);
tcase_add_test(tc_bitset, test_bitset);
tcase_add_test(tc_bitset, test_bitset_set);
tcase_add_test(tc_bitset, test_bitset_clear);
suite_add_tcase(s, tc_bit);
suite_add_tcase(s, tc_bitset);
return s;
}
int main(void)
{
int number_failed;
Suite *s = bitset_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

122
tests/unit/check_client.c Normal file
View File

@@ -0,0 +1,122 @@
#include <check.h>
#include <stdio.h>
#include "self_pipe.h"
#include "nbdtypes.h"
#include "serve.h"
#include "client.h"
#include <unistd.h>
struct server fake_server = {0};
#define FAKE_SERVER &fake_server
#define FAKE_SOCKET (42)
START_TEST( test_assigns_socket )
{
struct client * c;
c = client_create( FAKE_SERVER, FAKE_SOCKET );
fail_unless( 42 == c->socket, "Socket wasn't assigned." );
}
END_TEST
START_TEST( test_assigns_server )
{
struct client * c;
/* can't predict the storage size so we can't allocate one on
* the stack
*/
c = client_create( FAKE_SERVER, FAKE_SOCKET );
fail_unless( FAKE_SERVER == c->serve, "Serve wasn't assigned." );
}
END_TEST
START_TEST( test_opens_stop_signal )
{
struct client *c = client_create( FAKE_SERVER, FAKE_SOCKET );
client_signal_stop( c );
fail_unless( 1 == self_pipe_signal_clear( c->stop_signal ),
"No signal was sent." );
}
END_TEST
int fd_is_closed(int);
START_TEST( test_closes_stop_signal )
{
struct client *c = client_create( FAKE_SERVER, FAKE_SOCKET );
int read_fd = c->stop_signal->read_fd;
int write_fd = c->stop_signal->write_fd;
client_destroy( c );
fail_unless( fd_is_closed( read_fd ), "Stop signal wasn't destroyed." );
fail_unless( fd_is_closed( write_fd ), "Stop signal wasn't destroyed." );
}
END_TEST
START_TEST( test_read_request_quits_on_stop_signal )
{
int fds[2];
struct nbd_request nbdr;
pipe( fds );
struct client *c = client_create( FAKE_SERVER, fds[0] );
client_signal_stop( c );
int client_read_request( struct client *, struct nbd_request *);
fail_unless( 0 == client_read_request( c, &nbdr ), "Didn't quit on stop." );
close( fds[0] );
close( fds[1] );
}
END_TEST
Suite *client_suite(void)
{
Suite *s = suite_create("client");
TCase *tc_create = tcase_create("create");
TCase *tc_signal = tcase_create("signal");
TCase *tc_destroy = tcase_create("destroy");
tcase_add_test(tc_create, test_assigns_socket);
tcase_add_test(tc_create, test_assigns_server);
tcase_add_test(tc_signal, test_opens_stop_signal);
tcase_add_test(tc_signal, test_read_request_quits_on_stop_signal);
tcase_add_test( tc_destroy, test_closes_stop_signal );
suite_add_tcase(s, tc_create);
suite_add_tcase(s, tc_signal);
suite_add_tcase(s, tc_destroy);
return s;
}
int main(void)
{
int number_failed;
Suite *s = client_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

View File

@@ -0,0 +1,42 @@
#include "control.h"
#include "flexnbd.h"
#include <check.h>
START_TEST( test_assigns_sock_name )
{
struct flexnbd flexnbd = {0};
char csn[] = "foobar";
struct control * control = control_create(&flexnbd, csn );
fail_unless( csn == control->socket_name, "Socket name not assigned" );
}
END_TEST
Suite *control_suite(void)
{
Suite *s = suite_create("control");
TCase *tc_create = tcase_create("create");
tcase_add_test(tc_create, test_assigns_sock_name);
suite_add_tcase( s, tc_create );
return s;
}
int main(void)
{
int number_failed;
Suite *s = control_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

View File

@@ -0,0 +1,47 @@
#include "flexnbd.h"
#include <check.h>
START_TEST( test_listening_assigns_sock )
{
struct flexnbd * flexnbd = flexnbd_create_listening(
"127.0.0.1",
NULL,
"4777",
NULL,
"fakefile",
"fakesock",
0,
0,
NULL,
1 );
fail_if( NULL == flexnbd->control->socket_name, "No socket was copied" );
}
END_TEST
Suite *flexnbd_suite(void)
{
Suite *s = suite_create("flexnbd");
TCase *tc_create = tcase_create("create");
tcase_add_test(tc_create, test_listening_assigns_sock);
suite_add_tcase( s, tc_create );
return s;
}
int main(void)
{
int number_failed;
Suite *s = flexnbd_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

134
tests/unit/check_ioutil.c Normal file
View File

@@ -0,0 +1,134 @@
#include "ioutil.h"
#include <check.h>
START_TEST( test_read_until_newline_returns_line_length_plus_null )
{
int fds[2];
int nread;
char buf[5] = {0};
pipe(fds);
write( fds[1], "1234\n", 5 );
nread = read_until_newline( fds[0], buf, 5 );
ck_assert_int_eq( 5, nread );
}
END_TEST
START_TEST( test_read_until_newline_inserts_null )
{
int fds[2];
int nread;
char buf[5] = {0};
pipe(fds);
write( fds[1], "1234\n", 5 );
nread = read_until_newline( fds[0], buf, 5 );
ck_assert_int_eq( '\0', buf[4] );
}
END_TEST
START_TEST( test_read_empty_line_inserts_null )
{
int fds[2];
int nread;
char buf[5] = {0};
pipe(fds);
write( fds[1], "\n", 1 );
nread = read_until_newline( fds[0], buf, 1 );
ck_assert_int_eq( '\0', buf[0] );
ck_assert_int_eq( 1, nread );
}
END_TEST
START_TEST( test_read_eof_returns_err )
{
int fds[2];
int nread;
char buf[5] = {0};
pipe( fds );
close( fds[1] );
nread = read_until_newline( fds[0], buf, 5 );
ck_assert_int_eq( -1, nread );
}
END_TEST
START_TEST( test_read_eof_fills_line )
{
int fds[2];
int nread;
char buf[5] = {0};
pipe(fds);
write( fds[1], "1234", 4 );
close( fds[1] );
nread = read_until_newline( fds[0], buf, 5 );
ck_assert_int_eq( -1, nread );
ck_assert_int_eq( '4', buf[3] );
}
END_TEST
START_TEST( test_read_lines_until_blankline )
{
char **lines = NULL;
int fds[2];
int nlines;
pipe( fds );
write( fds[1], "a\nb\nc\n\n", 7 );
nlines = read_lines_until_blankline( fds[0], 256, &lines );
ck_assert_int_eq( 3, nlines );
}
END_TEST
Suite *ioutil_suite(void)
{
Suite *s = suite_create("ioutil");
TCase *tc_read_until_newline = tcase_create("read_until_newline");
TCase *tc_read_lines_until_blankline = tcase_create("read_lines_until_blankline");
tcase_add_test(tc_read_until_newline, test_read_until_newline_returns_line_length_plus_null);
tcase_add_test(tc_read_until_newline, test_read_until_newline_inserts_null);
tcase_add_test(tc_read_until_newline, test_read_empty_line_inserts_null);
tcase_add_test(tc_read_until_newline, test_read_eof_returns_err);
tcase_add_test(tc_read_until_newline, test_read_eof_fills_line );
tcase_add_test(tc_read_lines_until_blankline, test_read_lines_until_blankline );
suite_add_tcase(s, tc_read_until_newline);
suite_add_tcase(s, tc_read_lines_until_blankline);
return s;
}
int main(void)
{
int number_failed;
Suite *s = ioutil_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

57
tests/unit/check_listen.c Normal file
View File

@@ -0,0 +1,57 @@
#include "serve.h"
#include "listen.h"
#include "util.h"
#include "flexnbd.h"
#include <check.h>
#include <string.h>
START_TEST( test_defaults_main_serve_opts )
{
struct flexnbd flexnbd;
struct listen * listen = listen_create( &flexnbd, "127.0.0.1", NULL, "4777", NULL,
"foo", 0, 0, NULL, 1 );
NULLCHECK( listen );
struct server *init_serve = listen->init_serve;
struct server *main_serve = listen->main_serve;
NULLCHECK( init_serve );
NULLCHECK( main_serve );
fail_unless( 0 == memcmp(&init_serve->bind_to,
&main_serve->bind_to,
sizeof( union mysockaddr )),
"Main serve bind_to was not set" );
}
END_TEST
Suite* listen_suite(void)
{
Suite *s = suite_create("listen");
TCase *tc_create = tcase_create("create");
tcase_add_exit_test(tc_create, test_defaults_main_serve_opts, 0);
suite_add_tcase(s, tc_create);
return s;
}
#ifdef DEBUG
# define LOG_LEVEL 0
#else
# define LOG_LEVEL 2
#endif
int main(void)
{
log_level = LOG_LEVEL;
int number_failed;
Suite *s = listen_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

104
tests/unit/check_mbox.c Normal file
View File

@@ -0,0 +1,104 @@
#include "mbox.h"
#include "util.h"
#include <pthread.h>
#include <check.h>
START_TEST( test_allocs_cvar )
{
struct mbox * mbox = mbox_create();
fail_if( NULL == mbox, "Nothing allocated" );
pthread_cond_t cond_zero;
/* A freshly inited pthread_cond_t is set to {0} */
memset( &cond_zero, 'X', sizeof( cond_zero ) );
fail_if( memcmp( &cond_zero, &mbox->filled_cond, sizeof( cond_zero ) ) == 0 ,
"Condition variable not allocated" );
fail_if( memcmp( &cond_zero, &mbox->emptied_cond, sizeof( cond_zero ) ) == 0 ,
"Condition variable not allocated" );
}
END_TEST
START_TEST( test_post_stores_value )
{
struct mbox * mbox = mbox_create();
void * deadbeef = (void *)0xDEADBEEF;
mbox_post( mbox, deadbeef );
fail_unless( deadbeef == mbox_contents( mbox ),
"Contents were not posted" );
}
END_TEST
void * mbox_receive_runner( void * mbox_uncast )
{
struct mbox * mbox = (struct mbox *)mbox_uncast;
void * contents = NULL;
contents = mbox_receive( mbox );
return contents;
}
START_TEST( test_receive_blocks_until_post )
{
struct mbox * mbox = mbox_create();
pthread_t receiver;
pthread_create( &receiver, NULL, mbox_receive_runner, mbox );
void * deadbeef = (void *)0xDEADBEEF;
void * retval =NULL;
usleep(10000);
fail_unless( EBUSY == pthread_tryjoin_np( receiver, &retval ),
"Receiver thread wasn't blocked");
mbox_post( mbox, deadbeef );
fail_unless( 0 == pthread_join( receiver, &retval ),
"Failed to join the receiver thread" );
fail_unless( retval == deadbeef,
"Return value was wrong" );
}
END_TEST
Suite* acl_suite(void)
{
Suite *s = suite_create("acl");
TCase *tc_create = tcase_create("create");
TCase *tc_post = tcase_create("post");
tcase_add_test(tc_create, test_allocs_cvar);
tcase_add_test( tc_post, test_post_stores_value );
tcase_add_test( tc_post, test_receive_blocks_until_post);
suite_add_tcase(s, tc_create);
suite_add_tcase(s, tc_post);
return s;
}
int main(void)
{
#ifdef DEBUG
log_level = 0;
#else
log_level = 2;
#endif
int number_failed;
Suite *s = acl_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
log_level = 0;
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

223
tests/unit/check_nbdtypes.c Normal file
View File

@@ -0,0 +1,223 @@
#include <check.h>
#include "nbdtypes.h"
START_TEST(test_init_passwd)
{
struct nbd_init_raw init_raw;
struct nbd_init init;
memcpy( init_raw.passwd, INIT_PASSWD, 8 );
nbd_r2h_init( &init_raw, &init );
memset( init_raw.passwd, 0, 8 );
nbd_h2r_init( &init, &init_raw );
fail_unless( memcmp( init.passwd, INIT_PASSWD, 8 ) == 0, "The password was not copied." );
fail_unless( memcmp( init_raw.passwd, INIT_PASSWD, 8 ) == 0, "The password was not copied back." );
}
END_TEST
START_TEST(test_init_magic)
{
struct nbd_init_raw init_raw;
struct nbd_init init;
init_raw.magic = 12345;
nbd_r2h_init( &init_raw, &init );
fail_unless( be64toh( 12345 ) == init.magic, "Magic was not converted." );
init.magic = 67890;
nbd_h2r_init( &init, &init_raw );
fail_unless( htobe64( 67890 ) == init_raw.magic, "Magic was not converted back." );
}
END_TEST
START_TEST(test_init_size)
{
struct nbd_init_raw init_raw;
struct nbd_init init;
init_raw.size = 12345;
nbd_r2h_init( &init_raw, &init );
fail_unless( be64toh( 12345 ) == init.size, "Size was not converted." );
init.size = 67890;
nbd_h2r_init( &init, &init_raw );
fail_unless( htobe64( 67890 ) == init_raw.size, "Size was not converted back." );
}
END_TEST
START_TEST(test_request_magic )
{
struct nbd_request_raw request_raw;
struct nbd_request request;
request_raw.magic = 12345;
nbd_r2h_request( &request_raw, &request );
fail_unless( be32toh( 12345 ) == request.magic, "Magic was not converted." );
request.magic = 67890;
nbd_h2r_request( &request, &request_raw );
fail_unless( htobe32( 67890 ) == request_raw.magic, "Magic was not converted back." );
}
END_TEST
START_TEST(test_request_type )
{
struct nbd_request_raw request_raw;
struct nbd_request request;
request_raw.type = 12345;
nbd_r2h_request( &request_raw, &request );
fail_unless( be32toh( 12345 ) == request.type, "Type was not converted." );
request.type = 67890;
nbd_h2r_request( &request, &request_raw );
fail_unless( htobe32( 67890 ) == request_raw.type, "Type was not converted back." );
}
END_TEST
START_TEST(test_request_handle)
{
struct nbd_request_raw request_raw;
struct nbd_request request;
memcpy( request_raw.handle, "MYHANDLE", 8 );
nbd_r2h_request( &request_raw, &request );
memset( request_raw.handle, 0, 8 );
nbd_h2r_request( &request, &request_raw );
fail_unless( memcmp( request.handle, "MYHANDLE", 8 ) == 0, "The handle was not copied." );
fail_unless( memcmp( request_raw.handle, "MYHANDLE", 8 ) == 0, "The handle was not copied back." );
}
END_TEST
START_TEST(test_request_from )
{
struct nbd_request_raw request_raw;
struct nbd_request request;
request_raw.from = 12345;
nbd_r2h_request( &request_raw, &request );
fail_unless( be64toh( 12345 ) == request.from, "From was not converted." );
request.from = 67890;
nbd_h2r_request( &request, &request_raw );
fail_unless( htobe64( 67890 ) == request_raw.from, "From was not converted back." );
}
END_TEST
START_TEST(test_request_len )
{
struct nbd_request_raw request_raw;
struct nbd_request request;
request_raw.len = 12345;
nbd_r2h_request( &request_raw, &request );
fail_unless( be32toh( 12345 ) == request.len, "Type was not converted." );
request.len = 67890;
nbd_h2r_request( &request, &request_raw );
fail_unless( htobe32( 67890 ) == request_raw.len, "Type was not converted back." );
}
END_TEST
START_TEST(test_reply_magic )
{
struct nbd_reply_raw reply_raw;
struct nbd_reply reply;
reply_raw.magic = 12345;
nbd_r2h_reply( &reply_raw, &reply );
fail_unless( be32toh( 12345 ) == reply.magic, "Magic was not converted." );
reply.magic = 67890;
nbd_h2r_reply( &reply, &reply_raw );
fail_unless( htobe32( 67890 ) == reply_raw.magic, "Magic was not converted back." );
}
END_TEST
START_TEST(test_reply_error )
{
struct nbd_reply_raw reply_raw;
struct nbd_reply reply;
reply_raw.error = 12345;
nbd_r2h_reply( &reply_raw, &reply );
fail_unless( be32toh( 12345 ) == reply.error, "Error was not converted." );
reply.error = 67890;
nbd_h2r_reply( &reply, &reply_raw );
fail_unless( htobe32( 67890 ) == reply_raw.error, "Error was not converted back." );
}
END_TEST
START_TEST(test_reply_handle)
{
struct nbd_reply_raw reply_raw;
struct nbd_reply reply;
memcpy( reply_raw.handle, "MYHANDLE", 8 );
nbd_r2h_reply( &reply_raw, &reply );
memset( reply_raw.handle, 0, 8 );
nbd_h2r_reply( &reply, &reply_raw );
fail_unless( memcmp( reply.handle, "MYHANDLE", 8 ) == 0, "The handle was not copied." );
fail_unless( memcmp( reply_raw.handle, "MYHANDLE", 8 ) == 0, "The handle was not copied back." );
}
END_TEST
Suite *nbdtypes_suite(void)
{
Suite *s = suite_create( "nbdtypes" );
TCase *tc_init = tcase_create( "nbd_init" );
TCase *tc_request = tcase_create( "nbd_request" );
TCase *tc_reply = tcase_create( "nbd_reply" );
tcase_add_test( tc_init, test_init_passwd );
tcase_add_test( tc_init, test_init_magic );
tcase_add_test( tc_init, test_init_size );
tcase_add_test( tc_request, test_request_magic );
tcase_add_test( tc_request, test_request_type );
tcase_add_test( tc_request, test_request_handle );
tcase_add_test( tc_request, test_request_from );
tcase_add_test( tc_request, test_request_len );
tcase_add_test( tc_reply, test_reply_magic );
tcase_add_test( tc_reply, test_reply_error );
tcase_add_test( tc_reply, test_reply_handle );
suite_add_tcase( s, tc_init );
suite_add_tcase( s, tc_request );
suite_add_tcase( s, tc_reply );
return s;
}
int main(void)
{
int number_failed;
Suite *s = nbdtypes_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

47
tests/unit/check_parse.c Normal file
View File

@@ -0,0 +1,47 @@
#include "parse.h"
#include "util.h"
#include <check.h>
START_TEST( test_can_parse_ip_address_twice )
{
char ip_address[] = "127.0.0.1";
struct sockaddr saddr;
parse_ip_to_sockaddr( &saddr, ip_address );
parse_ip_to_sockaddr( &saddr, ip_address );
}
END_TEST
Suite* parse_suite(void)
{
Suite *s = suite_create("parse");
TCase *tc_create = tcase_create("ip_to_sockaddr");
tcase_add_test(tc_create, test_can_parse_ip_address_twice);
suite_add_tcase(s, tc_create);
return s;
}
#ifdef DEBUG
# define LOG_LEVEL 0
#else
# define LOG_LEVEL 2
#endif
int main(void)
{
log_level = LOG_LEVEL;
int number_failed;
Suite *s = parse_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

View File

@@ -0,0 +1,197 @@
#include "readwrite.h"
#include <check.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <stddef.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "util.h"
#include "nbdtypes.h"
int fd_read_request( int, struct nbd_request_raw *);
int fd_write_reply( int, char *, int );
int marker;
void error_marker(void * unused __attribute__((unused)),
int fatal __attribute__((unused)))
{
marker = 1;
return;
}
struct respond {
int sock_fds[2]; // server end
int do_fail;
pthread_t thread_id;
pthread_attr_t thread_attr;
struct nbd_request received;
};
void * responder( void *respond_uncast )
{
struct respond * resp = (struct respond *) respond_uncast;
int sock_fd = resp->sock_fds[1];
struct nbd_request_raw request_raw;
char wrong_handle[] = "WHOOPSIE";
if( fd_read_request( sock_fd, &request_raw ) == -1){
fprintf(stderr, "Problem with fd_read_request\n");
} else {
nbd_r2h_request( &request_raw, &resp->received);
if (resp->do_fail){
fd_write_reply( sock_fd, wrong_handle, 0 );
}
else {
fd_write_reply( sock_fd, resp->received.handle, 0 );
}
}
return NULL;
}
struct respond * respond_create( int do_fail )
{
struct respond * respond = (struct respond *)calloc( 1, sizeof( struct respond ) );
socketpair( PF_UNIX, SOCK_STREAM, 0, respond->sock_fds );
respond->do_fail = do_fail;
pthread_attr_init( &respond->thread_attr );
pthread_create( &respond->thread_id, &respond->thread_attr, responder, respond );
return respond;
}
void respond_destroy( struct respond * respond ){
NULLCHECK( respond );
pthread_join( respond->thread_id, NULL );
pthread_attr_destroy( &respond->thread_attr );
close( respond->sock_fds[0] );
close( respond->sock_fds[1] );
free( respond );
}
void * entruster( void * nothing __attribute__((unused)))
{
DECLARE_ERROR_CONTEXT( error_context );
error_set_handler( (cleanup_handler *)error_marker, error_context );
struct respond * respond = respond_create( 1 );
socket_nbd_entrust( respond->sock_fds[0] );
return NULL;
}
START_TEST( test_rejects_mismatched_handle )
{
error_init();
pthread_t entruster_thread;
log_level=5;
marker = 0;
pthread_create( &entruster_thread, NULL, entruster, NULL );
FATAL_UNLESS( 0 == pthread_join( entruster_thread, NULL ), "pthread_join failed");
log_level=2;
fail_unless( marker == 1, "Error handler wasn't called" );
}
END_TEST
START_TEST( test_accepts_matched_handle )
{
struct respond * respond = respond_create( 0 );
socket_nbd_entrust( respond->sock_fds[0] );
respond_destroy( respond );
}
END_TEST
START_TEST( test_entrust_type_sent )
{
struct respond * respond = respond_create( 0 );
socket_nbd_entrust( respond->sock_fds[0] );
fail_unless( respond->received.type == REQUEST_ENTRUST, "Wrong type sent." );
respond_destroy( respond );
}
END_TEST
START_TEST( test_disconnect_doesnt_read_reply )
{
struct respond * respond = respond_create( 1 );
socket_nbd_disconnect( respond->sock_fds[0] );
respond_destroy( respond );
}
END_TEST
Suite* readwrite_suite(void)
{
Suite *s = suite_create("acl");
TCase *tc_transfer = tcase_create("entrust");
TCase *tc_disconnect = tcase_create("disconnect");
tcase_add_test(tc_transfer, test_rejects_mismatched_handle);
tcase_add_exit_test(tc_transfer, test_accepts_matched_handle, 0);
tcase_add_test( tc_transfer, test_entrust_type_sent );
/* This test is a little funny. We respond with a dodgy handle
* and check that this *doesn't* cause a message rejection,
* because we want to know that the sender won't even try to
* read the response.
*/
tcase_add_exit_test( tc_disconnect, test_disconnect_doesnt_read_reply,0 );
suite_add_tcase(s, tc_transfer);
suite_add_tcase(s, tc_disconnect);
return s;
}
#ifdef DEBUG
# define LOG_LEVEL 0
#else
# define LOG_LEVEL 2
#endif
int main(void)
{
log_level = LOG_LEVEL;
int number_failed;
Suite *s = readwrite_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
log_level = 0;
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

View File

@@ -0,0 +1,198 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <check.h>
#include <mcheck.h>
#include "self_pipe.h"
START_TEST( test_opens_pipe )
{
struct self_pipe* sig;
char buf[] = " ";
sig = self_pipe_create();
write( sig->write_fd, "1", 1 );
read( sig->read_fd, buf, 1 );
fail_unless( buf[0] == '1', "Pipe does not seem to be open;" );
self_pipe_destroy( sig );
}
END_TEST
void * signal_thread( void * thing )
{
struct self_pipe *sig = (struct self_pipe *)thing;
usleep( 100000 );
self_pipe_signal( sig );
return NULL;
}
pthread_t start_signal_thread( struct self_pipe *sig )
{
pthread_attr_t attr;
pthread_t thread_id;
pthread_attr_init( &attr );
pthread_create( &thread_id, &attr, signal_thread, sig );
pthread_attr_destroy( &attr );
return thread_id;
}
START_TEST( test_signals )
{
struct self_pipe* sig;
fd_set fds;
pthread_t signal_thread_id;
sig = self_pipe_create();
FD_ZERO( &fds );
self_pipe_fd_set( sig, &fds );
signal_thread_id = start_signal_thread( sig );
if ( select( FD_SETSIZE, &fds, NULL, NULL, NULL ) == -1 ) {
fail( strerror(errno) );
}
self_pipe_signal_clear( sig );
fail_unless( self_pipe_fd_isset( sig, &fds ), "Signalled pipe was not FD_ISSET." );
pthread_join( signal_thread_id, NULL );
self_pipe_destroy( sig );
}
END_TEST
START_TEST( test_clear_returns_immediately )
{
struct self_pipe *sig;
sig = self_pipe_create();
fail_unless( 0 == self_pipe_signal_clear( sig ), "Wrong clear result." );
}
END_TEST
START_TEST( test_destroy_closes_read_pipe )
{
struct self_pipe* sig;
ssize_t read_len;
int orig_read_fd;
sig = self_pipe_create();
orig_read_fd = sig->read_fd;
self_pipe_destroy( sig );
while( (read_len = read( orig_read_fd, "", 0 )) == -1 && errno == EINTR );
switch( read_len ) {
case 0:
fail("The read fd wasn't closed." );
break;
case -1:
switch(errno) {
case EBADF:
/* This is what we want */
break;
case EAGAIN:
fail( "The read fd wasn't closed." );
break;
default:
fail( strerror( errno ) );
break;
}
break;
default:
fail( "The read fd wasn't closed, and had data in it." );
break;
}
}
END_TEST
START_TEST( test_destroy_closes_write_pipe )
{
struct self_pipe * sig;
ssize_t write_len;
int orig_write_fd;
sig = self_pipe_create();
orig_write_fd = sig->write_fd;
self_pipe_destroy( sig );
while ( ( write_len = write( orig_write_fd, "", 0 ) ) == -1 && errno == EINTR );
switch( write_len ) {
case 0:
fail( "The write fd wasn't closed." );
break;
case -1:
switch( errno ) {
case EPIPE:
case EBADF:
/* This is what we want */
break;
case EAGAIN:
fail("The write fd wasn't closed." );
break;
default:
fail( strerror( errno ) );
break;
}
break;
default:
/* To get here, the write(_,_,0) would have to
* write some bytes.
*/
fail( "The write fd wasn't closed, and something REALLY WEIRD is going on." );
break;
}
}
END_TEST
Suite *self_pipe_suite(void)
{
Suite *s = suite_create("self_pipe");
TCase *tc_create = tcase_create("create");
TCase *tc_signal = tcase_create("signal");
TCase *tc_destroy = tcase_create("destroy");
tcase_add_test(tc_create, test_opens_pipe);
tcase_add_test(tc_signal, test_signals );
tcase_add_test(tc_signal, test_clear_returns_immediately );
tcase_add_test(tc_destroy, test_destroy_closes_read_pipe );
tcase_add_test(tc_destroy, test_destroy_closes_write_pipe );
/* We don't test that destroy free()'s the self_pipe pointer because
* that'll be caught by valgrind.
*/
suite_add_tcase(s, tc_create);
suite_add_tcase(s, tc_signal);
suite_add_tcase(s, tc_destroy);
return s;
}
int main(void)
{
int number_failed;
Suite *s = self_pipe_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

261
tests/unit/check_serve.c Normal file
View File

@@ -0,0 +1,261 @@
#include "serve.h"
#include "util.h"
#include "self_pipe.h"
#include "client.h"
#include "flexnbd.h"
#include <stdlib.h>
#include <check.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef DEBUG
# define LOG_LEVEL 0
#else
# define LOG_LEVEL 2
#endif
/* Need these because libcheck is braindead and doesn't
* run teardown after a failing test
*/
#define myfail( msg ) do { teardown(); fail(msg); } while (0)
#define myfail_if( tst, msg ) do { if( tst ) { myfail( msg ); } } while (0)
#define myfail_unless( tst, msg ) myfail_if( !(tst), msg )
char * dummy_file;
char *make_tmpfile(void)
{
FILE *fp;
char *fn_buf;
char leader[] = "/tmp/check_serve";
fn_buf = (char *)malloc( 1024 );
strncpy( fn_buf, leader, sizeof( leader ) - 1);
snprintf( &fn_buf[sizeof( leader ) - 1], 10, "%d", getpid() );
fp = fopen( fn_buf, "w" );
fwrite( fn_buf, 1024, 1, fp );
fclose( fp );
return fn_buf;
}
void setup( void )
{
dummy_file = make_tmpfile();
}
void teardown( void )
{
if( dummy_file ){ unlink( dummy_file ); }
free( dummy_file );
dummy_file = NULL;
}
START_TEST( test_replaces_acl )
{
struct flexnbd flexnbd;
struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 1 );
struct acl * new_acl = acl_create( 0, NULL, 0 );
server_replace_acl( s, new_acl );
myfail_unless( s->acl == new_acl, "ACL wasn't replaced." );
server_destroy( s );
}
END_TEST
START_TEST( test_signals_acl_updated )
{
struct flexnbd flexnbd;
struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 1 );
struct acl * new_acl = acl_create( 0, NULL, 0 );
server_replace_acl( s, new_acl );
myfail_unless( 1 == self_pipe_signal_clear( s->acl_updated_signal ),
"No signal sent." );
server_destroy( s );
}
END_TEST
int connect_client( char *addr, int actual_port, char *source_addr )
{
int client_fd;
struct addrinfo hint;
struct addrinfo *ailist, *aip;
memset( &hint, '\0', sizeof( struct addrinfo ) );
hint.ai_socktype = SOCK_STREAM;
myfail_if( getaddrinfo( addr, NULL, &hint, &ailist ) != 0, "getaddrinfo failed." );
int connected = 0;
for( aip = ailist; aip; aip = aip->ai_next ) {
((struct sockaddr_in *)aip->ai_addr)->sin_port = htons( actual_port );
client_fd = socket( aip->ai_family, aip->ai_socktype, aip->ai_protocol );
if (source_addr) {
struct sockaddr src;
if( !parse_ip_to_sockaddr(&src, source_addr)) {
close(client_fd);
continue;
}
bind(client_fd, &src, sizeof(struct sockaddr_in6));
}
if( client_fd == -1) { continue; }
if( connect( client_fd, aip->ai_addr, aip->ai_addrlen) == 0 ) {
connected = 1;
break;
}
close( client_fd );
}
myfail_unless( connected, "Didn't connect." );
return client_fd;
}
/* These are "internal" functions we need for the following test. We
* shouldn't need them but there's no other way at the moment. */
void serve_open_server_socket( struct server * );
int server_port( struct server * );
void server_accept( struct server * );
int fd_is_closed( int );
void server_close_clients( struct server * );
START_TEST( test_acl_update_closes_bad_client )
{
/* This is the wrong way round. Rather than pulling the thread
* and socket out of the server structure, we should be testing
* a client socket.
*/
struct flexnbd flexnbd;
flexnbd.signal_fd = -1;
struct server * s = server_create( &flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL, 1, 1 );
struct acl * new_acl = acl_create( 0, NULL, 1 );
struct client * c;
struct client_tbl_entry * entry;
int actual_port;
int client_fd;
int server_fd;
serve_open_server_socket( s );
actual_port = server_port( s );
client_fd = connect_client( "127.0.0.7", actual_port, "127.0.0.1" );
server_accept( s );
entry = &s->nbd_client[0];
c = entry->client;
/* At this point there should be an entry in the nbd_clients
* table and a background thread to run the client loop
*/
myfail_if( entry->thread == 0, "No client thread was started." );
server_fd = c->socket;
myfail_if( fd_is_closed(server_fd),
"Sanity check failed - client socket wasn't open." );
server_replace_acl( s, new_acl );
/* accept again, so that we can react to the acl replacement signal */
server_accept( s );
/* Fail if we time out here */
while( !fd_is_closed( server_fd ) );
close( client_fd );
server_close_clients( s );
server_destroy( s );
}
END_TEST
START_TEST( test_acl_update_leaves_good_client )
{
struct flexnbd flexnbd;
struct server * s = server_create( &flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL, 1, 1 );
char *lines[] = {"127.0.0.1"};
struct acl * new_acl = acl_create( 1, lines, 1 );
struct client * c;
struct client_tbl_entry * entry;
int actual_port;
int client_fd;
int server_fd;
serve_open_server_socket( s );
actual_port = server_port( s );
client_fd = connect_client( "127.0.0.7", actual_port, "127.0.0.1" );
server_accept( s );
entry = &s->nbd_client[0];
c = entry->client;
/* At this point there should be an entry in the nbd_clients
* table and a background thread to run the client loop
*/
myfail_if( entry->thread == 0, "No client thread was started." );
server_fd = c->socket;
myfail_if( fd_is_closed(server_fd),
"Sanity check failed - client socket wasn't open." );
server_replace_acl( s, new_acl );
server_accept( s );
myfail_if( self_pipe_signal_clear( c->stop_signal ),
"Client was told to stop." );
close( client_fd );
server_close_clients( s );
server_destroy( s );
}
END_TEST
Suite* serve_suite(void)
{
Suite *s = suite_create("serve");
TCase *tc_acl_update = tcase_create("acl_update");
tcase_add_checked_fixture( tc_acl_update, setup, NULL );
tcase_add_test(tc_acl_update, test_replaces_acl);
tcase_add_test(tc_acl_update, test_signals_acl_updated);
tcase_add_exit_test(tc_acl_update, test_acl_update_closes_bad_client, 0);
tcase_add_exit_test(tc_acl_update, test_acl_update_leaves_good_client, 0);
suite_add_tcase(s, tc_acl_update);
return s;
}
int main(void)
{
log_level = LOG_LEVEL;
error_init();
int number_failed;
Suite *s = serve_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

139
tests/unit/check_status.c Normal file
View File

@@ -0,0 +1,139 @@
#include "status.h"
#include "serve.h"
#include "ioutil.h"
#include "util.h"
#include <check.h>
START_TEST( test_status_create )
{
struct server server;
struct status *status = NULL;
status = status_create( &server );
fail_if( NULL == status, "Status wasn't allocated" );
status_destroy( status );
}
END_TEST
START_TEST( test_gets_has_control )
{
struct server server;
struct status * status;
server.has_control = 1;
status = status_create( &server );
fail_unless( status->has_control == 1, "has_control wasn't copied" );
status_destroy( status );
}
END_TEST
START_TEST( test_gets_is_mirroring )
{
struct server server;
struct status * status;
server.mirror = NULL;
status = status_create( &server );
fail_if( status->is_mirroring, "is_mirroring was set" );
status_destroy( status );
server.mirror = (struct mirror_status *)xmalloc( sizeof( struct mirror_status ) );
status = status_create( &server );
fail_unless( status->is_mirroring, "is_mirroring wasn't set" );
status_destroy( status );
}
END_TEST
START_TEST( test_renders_has_control )
{
struct status status;
int fds[2];
pipe(fds);
char buf[1024] = {0};
status.has_control = 1;
status_write( &status, fds[1] );
fail_unless( read_until_newline( fds[0], buf, 1024 ) > 0,
"Couldn't read the result" );
char *found = strstr( buf, "has_control=true" );
fail_if( NULL == found, "has_control=true not found" );
status.has_control = 0;
status_write( &status, fds[1] );
fail_unless( read_until_newline( fds[0], buf, 1024 ) > 0,
"Couldn't read the result" );
found = strstr( buf, "has_control=false" );
fail_if( NULL == found, "has_control=false not found" );
}
END_TEST
START_TEST( test_renders_is_mirroring )
{
struct status status;
int fds[2];
pipe(fds);
char buf[1024] = {0};
status.is_mirroring = 1;
status_write( &status, fds[1] );
fail_unless( read_until_newline( fds[0], buf, 1024 ) > 0,
"Couldn't read the result" );
char *found = strstr( buf, "is_mirroring=true" );
fail_if( NULL == found, "is_mirroring=true not found" );
status.is_mirroring = 0;
status_write( &status, fds[1] );
fail_unless( read_until_newline( fds[0], buf, 1024 ) > 0,
"Couldn't read the result" );
found = strstr( buf, "is_mirroring=false" );
fail_if( NULL == found, "is_mirroring=false not found" );
}
END_TEST
Suite *status_suite(void)
{
Suite *s = suite_create("status");
TCase *tc_create = tcase_create("create");
TCase *tc_render = tcase_create("render");
tcase_add_test(tc_create, test_status_create);
tcase_add_test(tc_create, test_gets_has_control);
tcase_add_test(tc_create, test_gets_is_mirroring);
tcase_add_test(tc_render, test_renders_has_control);
tcase_add_test(tc_render, test_renders_is_mirroring);
suite_add_tcase(s, tc_create);
suite_add_tcase(s, tc_render);
return s;
}
int main(void)
{
int number_failed;
Suite *s = status_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}

172
tests/unit/check_util.c Normal file
View File

@@ -0,0 +1,172 @@
#include "util.h"
#include "self_pipe.h"
#include <check.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
struct cleanup_bucket {
struct self_pipe *called_signal;
};
struct cleanup_bucket bkt;
void bucket_init(void){
if ( bkt.called_signal ) {
self_pipe_destroy( bkt.called_signal );
}
bkt.called_signal = self_pipe_create();
}
void setup(void)
{
bkt.called_signal = NULL;
}
int handler_called(void)
{
return self_pipe_signal_clear( bkt.called_signal );
}
void dummy_cleanup( struct cleanup_bucket * foo, int fatal __attribute__((unused)) )
{
if (NULL != foo){
self_pipe_signal( foo->called_signal );
}
}
void trigger_fatal(void)
{
error_init();
error_set_handler( (cleanup_handler*) dummy_cleanup, &bkt );
log_level = 5;
fatal("Expected fatal error");
}
void trigger_error( void )
{
error_init();
error_set_handler( (cleanup_handler *) dummy_cleanup, &bkt);
log_level = 4;
error("Expected error");
}
START_TEST( test_fatal_kills_process )
{
pid_t pid;
pid = fork();
if ( pid == 0 ) {
trigger_fatal();
/* If we get here, just block so the test timeout fails
* us */
sleep(10);
}
else {
int kidstatus;
int result;
result = waitpid( pid, &kidstatus, 0 );
fail_if( result < 0, "Wait failed." );
fail_unless( kidstatus == 6, "Kid was not aborted." );
}
}
END_TEST
void * error_thread( void *nothing __attribute__((unused)) )
{
trigger_error();
return NULL;
}
START_TEST( test_error_doesnt_kill_process )
{
bucket_init();
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init( &attr );
pthread_create( &tid, &attr, error_thread, NULL );
pthread_join( tid, NULL );
}
END_TEST
START_TEST( test_error_calls_handler )
{
bucket_init();
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init( &attr );
pthread_create( &tid, &attr, error_thread, NULL );
pthread_join( tid, NULL );
fail_unless( handler_called(), "Handler wasn't called." );
}
END_TEST
START_TEST( test_fatal_doesnt_call_handler )
{
bucket_init();
pid_t kidpid;
kidpid = fork();
if ( kidpid == 0 ) {
trigger_fatal();
}
else {
int kidstatus;
int result = waitpid( kidpid, &kidstatus, 0 );
fail_if( result < 0, "Wait failed" );
fail_if( handler_called(), "Handler was called.");
}
}
END_TEST
Suite* error_suite(void)
{
Suite *s = suite_create("error");
TCase *tc_process = tcase_create("process");
TCase *tc_handler = tcase_create("handler");
tcase_add_checked_fixture( tc_process, setup, NULL );
tcase_add_test(tc_process, test_fatal_kills_process);
tcase_add_test(tc_process, test_error_doesnt_kill_process);
tcase_add_test(tc_handler, test_error_calls_handler );
tcase_add_test(tc_handler, test_fatal_doesnt_call_handler);
suite_add_tcase(s, tc_process);
suite_add_tcase(s, tc_handler);
return s;
}
int main(void)
{
int number_failed;
Suite *s = error_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? 0 : 1;
}