diff options
Diffstat (limited to 'test/regress_buffer.c')
-rw-r--r-- | test/regress_buffer.c | 261 |
1 files changed, 240 insertions, 21 deletions
diff --git a/test/regress_buffer.c b/test/regress_buffer.c index 1af75f5..02d557b 100644 --- a/test/regress_buffer.c +++ b/test/regress_buffer.c @@ -63,6 +63,8 @@ #include "regress.h" +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + /* Validates that an evbuffer is good. Returns false if it isn't, true if it * is*/ static int @@ -294,33 +296,39 @@ no_cleanup(const void *data, size_t datalen, void *extra) static void test_evbuffer_remove_buffer_with_empty(void *ptr) { - struct evbuffer *src = evbuffer_new(); - struct evbuffer *dst = evbuffer_new(); - char buf[2]; + struct evbuffer *src = evbuffer_new(); + struct evbuffer *dst = evbuffer_new(); + char buf[2] = { 'A', 'A' }; - evbuffer_validate(src); - evbuffer_validate(dst); + evbuffer_validate(src); + evbuffer_validate(dst); - /* setup the buffers */ - /* we need more data in src than we will move later */ - evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL); - evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL); - /* we need one buffer in dst and one empty buffer at the end */ - evbuffer_add(dst, buf, sizeof(buf)); - evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL); + /* setup the buffers */ + /* we need more data in src than we will move later */ + evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL); + evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL); + /* we need one buffer in dst and one empty buffer at the end */ + evbuffer_add(dst, buf, sizeof(buf)); + evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL); - evbuffer_validate(src); - evbuffer_validate(dst); + evbuffer_validate(src); + evbuffer_validate(dst); - /* move three bytes over */ - evbuffer_remove_buffer(src, dst, 3); + tt_mem_op(evbuffer_pullup(src, -1), ==, "AAAA", 4); + tt_mem_op(evbuffer_pullup(dst, -1), ==, "AA", 2); - evbuffer_validate(src); - evbuffer_validate(dst); + /* move three bytes over */ + evbuffer_remove_buffer(src, dst, 3); -end: - evbuffer_free(src); - evbuffer_free(dst); + evbuffer_validate(src); + evbuffer_validate(dst); + + tt_mem_op(evbuffer_pullup(src, -1), ==, "A", 1); + tt_mem_op(evbuffer_pullup(dst, -1), ==, "AAAAA", 5); + + end: + evbuffer_free(src); + evbuffer_free(dst); } static void @@ -350,6 +358,9 @@ test_evbuffer_remove_buffer_with_empty2(void *ptr) evbuffer_validate(src); evbuffer_validate(dst); + tt_mem_op(evbuffer_pullup(src, -1), ==, "foofoofoo", 9); + tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoo", 9); + evbuffer_remove_buffer(src, dst, 8); evbuffer_validate(src); @@ -358,6 +369,9 @@ test_evbuffer_remove_buffer_with_empty2(void *ptr) tt_int_op(evbuffer_get_length(src), ==, 1); tt_int_op(evbuffer_get_length(dst), ==, 17); + tt_mem_op(evbuffer_pullup(src, -1), ==, "o", 1); + tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoofoofoofo", 17); + end: evbuffer_free(src); evbuffer_free(dst); @@ -391,6 +405,9 @@ test_evbuffer_remove_buffer_with_empty3(void *ptr) evbuffer_validate(src); evbuffer_validate(dst); + tt_mem_op(evbuffer_pullup(src, -1), ==, "foofoo", 6); + tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoo", 6); + evbuffer_remove_buffer(src, dst, 5); evbuffer_validate(src); @@ -399,6 +416,9 @@ test_evbuffer_remove_buffer_with_empty3(void *ptr) tt_int_op(evbuffer_get_length(src), ==, 1); tt_int_op(evbuffer_get_length(dst), ==, 11); + tt_mem_op(evbuffer_pullup(src, -1), ==, "o", 1); + tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoofo", 11); + end: evbuffer_free(src); evbuffer_free(dst); @@ -406,6 +426,89 @@ test_evbuffer_remove_buffer_with_empty3(void *ptr) } static void +test_evbuffer_remove_buffer_with_empty_front(void *ptr) +{ + struct evbuffer *buf1 = NULL, *buf2 = NULL; + + buf1 = evbuffer_new(); + tt_assert(buf1); + + buf2 = evbuffer_new(); + tt_assert(buf2); + + tt_int_op(evbuffer_add_reference(buf1, "foo", 3, NULL, NULL), ==, 0); + tt_int_op(evbuffer_prepend(buf1, "", 0), ==, 0); + tt_int_op(evbuffer_remove_buffer(buf1, buf2, 1), ==, 1); + tt_int_op(evbuffer_add(buf1, "bar", 3), ==, 0); + tt_mem_op(evbuffer_pullup(buf1, -1), ==, "oobar", 5); + + evbuffer_validate(buf1); + evbuffer_validate(buf2); + + end: + if (buf1) + evbuffer_free(buf1); + if (buf2) + evbuffer_free(buf2); +} + +static void +test_evbuffer_remove_buffer_adjust_last_with_datap_with_empty(void *ptr) +{ + struct evbuffer *buf1 = NULL, *buf2 = NULL; + + buf1 = evbuffer_new(); + tt_assert(buf1); + + buf2 = evbuffer_new(); + tt_assert(buf2); + + tt_int_op(evbuffer_add(buf1, "aaaaaa", 6), ==, 0); + + // buf1: aaaaaab + // buf2: + { + struct evbuffer_iovec iovecs[2]; + /** we want two chains, to leave one chain empty */ + tt_int_op(evbuffer_reserve_space(buf1, 971, iovecs, 2), ==, 2); + tt_int_op(iovecs[0].iov_len, >=, 1); + tt_int_op(iovecs[1].iov_len, >=, 1); + tt_assert(*(char *)(iovecs[0].iov_base) = 'b'); + tt_assert(iovecs[0].iov_len = 1); + tt_int_op(evbuffer_commit_space(buf1, iovecs, 1), ==, 0); + } + + // buf1: aaaaaab + // buf2: dddcc + tt_int_op(evbuffer_add(buf2, "cc", 2), ==, 0); + tt_int_op(evbuffer_prepend(buf2, "ddd", 3), ==, 0); + + // buf1: + // buf2: aaaaaabdddcc + tt_int_op(evbuffer_prepend_buffer(buf2, buf1), ==, 0); + + // buf1: aaaaaabdddcc + // buf2: + tt_int_op(evbuffer_add_buffer(buf1, buf2), ==, 0); + + // buf1: c + // buf2: aaaaaabdddc + tt_int_op(evbuffer_remove_buffer(buf1, buf2, 11), ==, 11); + + // This fails today, we observe "aaaaaabcddd" instead! + tt_mem_op(evbuffer_pullup(buf2, -1), ==, "aaaaaabdddc", 11); + + evbuffer_validate(buf1); + evbuffer_validate(buf2); + + end: + if (buf1) + evbuffer_free(buf1); + if (buf2) + evbuffer_free(buf2); +} + +static void test_evbuffer_add_buffer_with_empty(void *ptr) { struct evbuffer *src = evbuffer_new(); @@ -635,6 +738,63 @@ end: } static void +test_evbuffer_reserve_with_empty(void *ptr) +{ + struct evbuffer *buf; + struct evbuffer_iovec v[2]; + + tt_assert(buf = evbuffer_new()); + evbuffer_add(buf, "a", 1); + tt_int_op(evbuffer_reserve_space(buf, 1<<12, v, 2), ==, 2); + v[0].iov_len = 1; + *(char *)v[0].iov_base = 'b'; + tt_int_op(evbuffer_commit_space(buf, v, 1), ==, 0); + evbuffer_add(buf, "c", 1); + tt_mem_op(evbuffer_pullup(buf, -1), ==, "abc", 2); + + evbuffer_validate(buf); + + end: + if (buf) + evbuffer_free(buf); +} + +/* regression for evbuffer_expand_fast_() with invalid last_with_datap that has + * been left after evbuffer_prepend() with empty chain in it */ +static void +test_evbuffer_reserve_invalid_last_with_datap(void *ptr) +{ + struct evbuffer *buf = NULL; + struct evbuffer_iovec vec[2]; + const int nvec = ARRAY_SIZE(vec); + int i, avec; + + buf = evbuffer_new(); + tt_assert(buf); + + /* prepend with an empty chain */ + evbuffer_add_reference(buf, "", 0, NULL, NULL); + evbuffer_prepend(buf, "foo", 3); + /* after invalid last_with_datap will create new chain */ + evbuffer_add(buf, "", 0); + /* we need to create at least 2 "used" (in evbuffer_expand_fast_()) chains */ + tt_int_op(avec = evbuffer_reserve_space(buf, 1<<12, vec, nvec), >=, 1); + for (i = 0; i < avec; ++i) + vec[i].iov_len = 0; + tt_int_op(evbuffer_commit_space(buf, vec, avec), ==, 0); + + /* and an actual problem, that triggers an assert(chain == buf->first) in + * evbuffer_expand_fast_() */ + tt_int_op(evbuffer_reserve_space(buf, 1<<13, vec, nvec), >=, 1); + + evbuffer_validate(buf); + +end: + if (buf) + evbuffer_free(buf); +} + +static void test_evbuffer_expand(void *ptr) { char data[4096]; @@ -2118,6 +2278,58 @@ end: } static void +test_evbuffer_empty_reference_prepend(void *ptr) +{ + struct evbuffer *buf = NULL; + + buf = evbuffer_new(); + tt_assert(buf); + + /** empty chain could leave invalid last_with_datap */ + evbuffer_add_reference(buf, "", 0, NULL, NULL); + evbuffer_validate(buf); + evbuffer_prepend(buf, "foo", 3); + + evbuffer_validate(buf); + tt_assert(!strncmp((char *)evbuffer_pullup(buf, -1), "foo", 3)); + evbuffer_validate(buf); + +end: + if (buf) + evbuffer_free(buf); +} +static void +test_evbuffer_empty_reference_prepend_buffer(void *ptr) +{ + struct evbuffer *buf1 = NULL, *buf2 = NULL; + + buf1 = evbuffer_new(); + tt_assert(buf1); + buf2 = evbuffer_new(); + tt_assert(buf2); + + /** empty chain could leave invalid last_with_datap */ + evbuffer_add_reference(buf1, "", 0, NULL, NULL); + evbuffer_validate(buf1); + evbuffer_add(buf2, "foo", 3); + evbuffer_validate(buf2); + evbuffer_prepend_buffer(buf2, buf1); + evbuffer_validate(buf2); + + tt_assert(!strncmp((char *)evbuffer_pullup(buf2, -1), "foo", 3)); + evbuffer_validate(buf2); + + tt_assert(!strncmp((char *)evbuffer_pullup(buf1, -1), "", 0)); + evbuffer_validate(buf2); + +end: + if (buf1) + evbuffer_free(buf1); + if (buf2) + evbuffer_free(buf2); +} + +static void test_evbuffer_peek_first_gt(void *info) { struct evbuffer *buf = NULL, *tmp_buf = NULL; @@ -2504,12 +2716,17 @@ struct testcase_t evbuffer_testcases[] = { { "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL }, { "remove_buffer_with_empty2", test_evbuffer_remove_buffer_with_empty2, 0, NULL, NULL }, { "remove_buffer_with_empty3", test_evbuffer_remove_buffer_with_empty3, 0, NULL, NULL }, + { "remove_buffer_with_empty_front", test_evbuffer_remove_buffer_with_empty_front, 0, NULL, NULL }, + { "remove_buffer_adjust_last_with_datap_with_empty", + test_evbuffer_remove_buffer_adjust_last_with_datap_with_empty, 0, NULL, NULL }, { "add_buffer_with_empty", test_evbuffer_add_buffer_with_empty, 0, NULL, NULL }, { "add_buffer_with_empty2", test_evbuffer_add_buffer_with_empty2, 0, NULL, NULL }, { "reserve2", test_evbuffer_reserve2, 0, NULL, NULL }, { "reserve_many", test_evbuffer_reserve_many, 0, NULL, NULL }, { "reserve_many2", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"add" }, { "reserve_many3", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"fill" }, + { "reserve_with_empty", test_evbuffer_reserve_with_empty, 0, NULL, NULL }, + { "reserve_invalid_last_with_datap", test_evbuffer_reserve_invalid_last_with_datap, TT_FORK, NULL, NULL }, { "expand", test_evbuffer_expand, 0, NULL, NULL }, { "expand_overflow", test_evbuffer_expand_overflow, 0, NULL, NULL }, { "add1", test_evbuffer_add1, 0, NULL, NULL }, @@ -2527,6 +2744,8 @@ struct testcase_t evbuffer_testcases[] = { { "multicast", test_evbuffer_multicast, 0, NULL, NULL }, { "multicast_drain", test_evbuffer_multicast_drain, 0, NULL, NULL }, { "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL }, + { "empty_reference_prepend", test_evbuffer_empty_reference_prepend, TT_FORK, NULL, NULL }, + { "empty_reference_prepend_buffer", test_evbuffer_empty_reference_prepend_buffer, TT_FORK, NULL, NULL }, { "peek", test_evbuffer_peek, 0, NULL, NULL }, { "peek_first_gt", test_evbuffer_peek_first_gt, 0, NULL, NULL }, { "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" }, |