Add dir/dump_unparseable_descriptors unit test

This commit is contained in:
Andrea Shepard 2016-06-25 08:32:16 +00:00
parent 2a17b93cc4
commit 824ee581b0

View file

@ -11,6 +11,7 @@
#define DIRVOTE_PRIVATE
#define ROUTER_PRIVATE
#define ROUTERLIST_PRIVATE
#define ROUTERPARSE_PRIVATE
#define HIBERNATE_PRIVATE
#define NETWORKSTATUS_PRIVATE
#define RELAY_PRIVATE
@ -4101,6 +4102,679 @@ test_dir_choose_compression_level(void* data)
done: ;
}
/*
* This really mocks options_get_datadir_fname2_suffix(), but for testing
* dump_desc(), we only care about get_datadir_fname(sub1), which is defined
* in config.h as:
*
* options_get_datadir_fname2_suffix(get_options(), sub1, NULL, NULL)
*/
static char *
mock_get_datadir_fname(const or_options_t *options,
const char *sub1, const char *sub2,
const char *suffix)
{
char *rv = NULL;
/*
* Assert we were called like get_datadir_fname(), since it's all
* we implement here.
*/
tt_assert(options != NULL);
tt_assert(sub1 != NULL);
tt_assert(sub2 == NULL);
tt_assert(suffix == NULL);
/* Just duplicate the basename and return it for this mock */
rv = strdup(sub1);
done:
return rv;
}
static char *last_unlinked_path = NULL;
static int unlinked_count = 0;
static void
mock_unlink_reset(void)
{
tor_free(last_unlinked_path);
unlinked_count = 0;
}
static int
mock_unlink(const char *path)
{
tt_assert(path != NULL);
tor_free(last_unlinked_path);
last_unlinked_path = tor_strdup(path);
++unlinked_count;
done:
return 0;
}
static char *last_write_str_path = NULL;
static uint8_t last_write_str_hash[DIGEST256_LEN];
static int write_str_count = 0;
static void
mock_write_str_to_file_reset(void)
{
tor_free(last_write_str_path);
write_str_count = 0;
}
static int
mock_write_str_to_file(const char *path, const char *str, int bin)
{
size_t len;
uint8_t hash[DIGEST256_LEN];
(void)bin;
tt_assert(path != NULL);
tt_assert(str != NULL);
len = strlen(str);
crypto_digest256((char *)hash, str, len, DIGEST_SHA256);
tor_free(last_write_str_path);
last_write_str_path = tor_strdup(path);
memcpy(last_write_str_hash, hash, sizeof(last_write_str_hash));
++write_str_count;
done:
return 0;
}
static void
test_dir_dump_unparseable_descriptors(void *data)
{
/*
* These bogus descriptors look nothing at all like real bogus descriptors
* we might see, but we're only testing dump_desc() here, not the parser.
*/
const char *test_desc_type = "squamous";
/* strlen(test_desc_1) = 583 bytes */
const char *test_desc_1 =
"The most merciful thing in the world, I think, is the inability of the "
"human mind to correlate all its contents. We live on a placid island of"
" ignorance in the midst of black seas of infinity, and it was not meant"
" that we should voyage far. The sciences, each straining in its own dir"
"ection, have hitherto harmed us little; but some day the piecing togeth"
"er of dissociated knowledge will open up such terrifying vistas of real"
"ity, and of our frightful position therein, that we shall either go mad"
"from the revelation or flee from the light into the peace and safety of"
"a new dark age.";
uint8_t test_desc_1_hash[DIGEST256_LEN];
char test_desc_1_hash_str[HEX_DIGEST256_LEN+1];
/* strlen(test_desc_2) = 650 bytes */
const char *test_desc_2 =
"I think their predominant colour was a greyish-green, though they had w"
"hite bellies. They were mostly shiny and slippery, but the ridges of th"
"eir backs were scaly. Their forms vaguely suggested the anthropoid, whi"
"le their heads were the heads of fish, with prodigious bulging eyes tha"
"t never closed. At the sides of their necks were palpitating gills, and"
"their long paws were webbed. They hopped irregularly, sometimes on two "
"legs and sometimes on four. I was somehow glad that they had no more th"
"an four limbs. Their croaking, baying voices, clearly wed tar articulat"
"e speech, held all the dark shades of expression which their staring fa"
"ces lacked.";
uint8_t test_desc_2_hash[DIGEST256_LEN];
char test_desc_2_hash_str[HEX_DIGEST256_LEN+1];
/* strlen(test_desc_3) = 700 bytes */
const char *test_desc_3 =
"Without knowing what futurism is like, Johansen achieved something very"
"close to it when he spoke of the city; for instead of describing any de"
"finite structure or building, he dwells only on broad impressions of va"
"st angles and stone surfaces - surfaces too great to belong to anything"
"right or proper for this earth, and impious with horrible images and hi"
"eroglyphs. I mention his talk about angles because it suggests somethin"
"g Wilcox had told me of his awful dreams. He said that the geometry of "
"the dream-place he saw was abnormal, non-Euclidean, and loathsomely red"
"olent of spheres and dimensions apart from ours. Now an unlettered seam"
"an felt the same thing whilst gazing at the terrible reality.";
uint8_t test_desc_3_hash[DIGEST256_LEN];
char test_desc_3_hash_str[HEX_DIGEST256_LEN+1];
/* strlen(test_desc_3) = 604 bytes */
const char *test_desc_4 =
"So we glanced back simultaneously, it would appear; though no doubt the"
"incipient motion of one prompted the imitation of the other. As we did "
"so we flashed both torches full strength at the momentarily thinned mis"
"t; either from sheer primitive anxiety to see all we could, or in a les"
"s primitive but equally unconscious effort to dazzle the entity before "
"we dimmed our light and dodged among the penguins of the labyrinth cent"
"er ahead. Unhappy act! Not Orpheus himself, or Lot's wife, paid much mo"
"re dearly for a backward glance. And again came that shocking, wide-ran"
"ged piping - \"Tekeli-li! Tekeli-li!\"";
uint8_t test_desc_4_hash[DIGEST256_LEN];
char test_desc_4_hash_str[HEX_DIGEST256_LEN+1];
(void)data;
/*
* Set up options mock so we can force a tiny FIFO size and generate
* cleanups.
*/
mock_options = malloc(sizeof(or_options_t));
reset_options(mock_options, &mock_get_options_calls);
mock_options->MaxUnparseableDescSizeToLog = 1536;
MOCK(get_options, mock_get_options);
MOCK(options_get_datadir_fname2_suffix,
mock_get_datadir_fname);
/*
* Set up unlink and write mocks
*/
MOCK(tor_unlink, mock_unlink);
mock_unlink_reset();
MOCK(write_str_to_file, mock_write_str_to_file);
mock_write_str_to_file_reset();
/*
* Compute hashes we'll need to recognize which descriptor is which
*/
crypto_digest256((char *)test_desc_1_hash, test_desc_1,
strlen(test_desc_1), DIGEST_SHA256);
base16_encode(test_desc_1_hash_str, sizeof(test_desc_1_hash_str),
(const char *)test_desc_1_hash,
sizeof(test_desc_1_hash));
crypto_digest256((char *)test_desc_2_hash, test_desc_2,
strlen(test_desc_2), DIGEST_SHA256);
base16_encode(test_desc_2_hash_str, sizeof(test_desc_2_hash_str),
(const char *)test_desc_2_hash,
sizeof(test_desc_2_hash));
crypto_digest256((char *)test_desc_3_hash, test_desc_3,
strlen(test_desc_3), DIGEST_SHA256);
base16_encode(test_desc_3_hash_str, sizeof(test_desc_3_hash_str),
(const char *)test_desc_3_hash,
sizeof(test_desc_3_hash));
crypto_digest256((char *)test_desc_4_hash, test_desc_4,
strlen(test_desc_4), DIGEST_SHA256);
base16_encode(test_desc_4_hash_str, sizeof(test_desc_4_hash_str),
(const char *)test_desc_4_hash,
sizeof(test_desc_4_hash));
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
tt_int_op(len_descs_dumped, ==, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
* (1) Fire off dump_desc() once; these descriptors should all be safely
* smaller than configured FIFO size.
*/
dump_desc(test_desc_1, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_1));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_1_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
tt_int_op(len_descs_dumped, ==, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
* Reset the mocks and check their state
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 0);
/*
* (2) Fire off dump_desc() twice; this still should trigger no cleanup.
*/
/* First time */
dump_desc(test_desc_2, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_2));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_2_hash, DIGEST_SHA256);
/* Second time */
dump_desc(test_desc_3, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_2) + strlen(test_desc_3));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_3_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
tt_int_op(len_descs_dumped, ==, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
* Reset the mocks and check their state
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 0);
/*
* (3) Three calls to dump_desc cause a FIFO cleanup
*/
/* First time */
dump_desc(test_desc_4, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/* Second time */
dump_desc(test_desc_1, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_4) + strlen(test_desc_1));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_1_hash, DIGEST_SHA256);
/* Third time - we should unlink the dump of test_desc_4 here */
dump_desc(test_desc_2, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_1) + strlen(test_desc_2));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 1);
tt_int_op(write_str_count, ==, 3);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_2_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
tt_int_op(len_descs_dumped, ==, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
* Reset the mocks and check their state
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 0);
/*
* (4) But repeating one (A B B) doesn't overflow and cleanup
*/
/* First time */
dump_desc(test_desc_3, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_3));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_3_hash, DIGEST_SHA256);
/* Second time */
dump_desc(test_desc_4, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_3) + strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/* Third time */
dump_desc(test_desc_4, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_3) + strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
tt_int_op(len_descs_dumped, ==, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
* Reset the mocks and check their state
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 0);
/*
* (5) Same for the (A B A) repetition
*/
/* First time */
dump_desc(test_desc_1, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_1));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_1_hash, DIGEST_SHA256);
/* Second time */
dump_desc(test_desc_2, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_1) + strlen(test_desc_2));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_2_hash, DIGEST_SHA256);
/* Third time */
dump_desc(test_desc_1, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_1) + strlen(test_desc_2));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_2_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
tt_int_op(len_descs_dumped, ==, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
* Reset the mocks and check their state
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 0);
/*
* (6) (A B B C) triggering overflow on C causes A, not B to be unlinked
*/
/* First time */
dump_desc(test_desc_3, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_3));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_3_hash, DIGEST_SHA256);
/* Second time */
dump_desc(test_desc_4, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_3) + strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/* Third time */
dump_desc(test_desc_4, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_3) + strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/* Fourth time - we should unlink the dump of test_desc_3 here */
dump_desc(test_desc_1, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_4) + strlen(test_desc_1));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 1);
tt_int_op(write_str_count, ==, 3);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_1_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
tt_int_op(len_descs_dumped, ==, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
* Reset the mocks and check their state
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 0);
/*
* (7) (A B A C) triggering overflow on C causes B, not A to be unlinked
*/
/* First time */
dump_desc(test_desc_2, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_2));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_2_hash, DIGEST_SHA256);
/* Second time */
dump_desc(test_desc_3, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_2) + strlen(test_desc_3));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_3_hash, DIGEST_SHA256);
/* Third time */
dump_desc(test_desc_2, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_2) + strlen(test_desc_3));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_3_hash, DIGEST_SHA256);
/* Fourth time - we should unlink the dump of test_desc_3 here */
dump_desc(test_desc_4, test_desc_type);
/*
* Assert things about the FIFO state
*/
tt_int_op(len_descs_dumped, ==, strlen(test_desc_2) + strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
tt_int_op(unlinked_count, ==, 1);
tt_int_op(write_str_count, ==, 3);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
tt_int_op(len_descs_dumped, ==, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
* Reset the mocks and check their state
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
tt_int_op(unlinked_count, ==, 0);
tt_int_op(write_str_count, ==, 0);
done:
/* Clean up the fifo */
dump_desc_fifo_cleanup();
/* Remove mocks */
UNMOCK(tor_unlink);
mock_unlink_reset();
UNMOCK(write_str_to_file);
mock_write_str_to_file_reset();
UNMOCK(options_get_datadir_fname2_suffix);
UNMOCK(get_options);
free(mock_options);
mock_options = NULL;
return;
}
static int mock_networkstatus_consensus_is_bootstrapping_value = 0;
static int
mock_networkstatus_consensus_is_bootstrapping(time_t now)
@ -4310,6 +4984,7 @@ struct testcase_t dir_tests[] = {
DIR(should_not_init_request_to_dir_auths_without_v3_info, 0),
DIR(should_init_request_to_dir_auths, 0),
DIR(choose_compression_level, 0),
DIR(dump_unparseable_descriptors, 0),
DIR_ARG(find_dl_schedule, TT_FORK, "bf"),
DIR_ARG(find_dl_schedule, TT_FORK, "ba"),
DIR_ARG(find_dl_schedule, TT_FORK, "cf"),