diff options
Diffstat (limited to 'test/core/transport/chttp2/stream_encoder_test.c')
-rw-r--r-- | test/core/transport/chttp2/stream_encoder_test.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/test/core/transport/chttp2/stream_encoder_test.c b/test/core/transport/chttp2/stream_encoder_test.c new file mode 100644 index 0000000000..3ee11d94e8 --- /dev/null +++ b/test/core/transport/chttp2/stream_encoder_test.c @@ -0,0 +1,320 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/stream_encoder.h" + +#include <stdio.h> + +#include "src/core/transport/chttp2/hpack_parser.h" +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/string.h> +#include "test/core/util/parse_hexstring.h" +#include "test/core/util/slice_splitter.h" +#include "test/core/util/test_config.h" + +#define TEST(x) run_test(x, #x) + +grpc_mdctx *g_mdctx; +grpc_chttp2_hpack_compressor g_compressor; +int g_failure = 0; +grpc_stream_op_buffer g_sopb; + +static gpr_slice create_test_slice(size_t length) { + gpr_slice slice = gpr_slice_malloc(length); + size_t i; + for (i = 0; i < length; i++) { + GPR_SLICE_START_PTR(slice)[i] = i; + } + return slice; +} + +/* verify that the output generated by encoding the stream matches the + hexstring passed in */ +static void verify_sopb(size_t window_available, int eof, + size_t expect_window_used, const char *expected) { + gpr_slice_buffer output; + gpr_slice merged; + gpr_slice expect = parse_hexstring(expected); + gpr_slice_buffer_init(&output); + GPR_ASSERT(expect_window_used == + grpc_chttp2_encode_some(g_sopb.ops, &g_sopb.nops, eof, &output, + window_available, 0xdeadbeef, + &g_compressor)); + merged = grpc_slice_merge(output.slices, output.count); + gpr_slice_buffer_destroy(&output); + + if (0 != gpr_slice_cmp(merged, expect)) { + char *expect_str = + gpr_hexdump((char *)GPR_SLICE_START_PTR(expect), + GPR_SLICE_LENGTH(expect), GPR_HEXDUMP_PLAINTEXT); + char *got_str = + gpr_hexdump((char *)GPR_SLICE_START_PTR(merged), + GPR_SLICE_LENGTH(merged), GPR_HEXDUMP_PLAINTEXT); + gpr_log(GPR_ERROR, "mismatched output for %s", expected); + gpr_log(GPR_ERROR, "EXPECT: %s", expect_str); + gpr_log(GPR_ERROR, "GOT: %s", got_str); + gpr_free(expect_str); + gpr_free(got_str); + g_failure = 1; + } + + gpr_slice_unref(merged); + gpr_slice_unref(expect); +} + +static void assert_result_ok(void *user_data, grpc_op_error error) { + GPR_ASSERT(error == GRPC_OP_OK); +} + +static void test_small_data_framing() { + grpc_sopb_add_no_op(&g_sopb); + verify_sopb(10, 0, 0, ""); + + grpc_sopb_add_flow_ctl_cb(&g_sopb, assert_result_ok, NULL); + grpc_sopb_add_slice(&g_sopb, create_test_slice(3)); + verify_sopb(10, 0, 3, "000003 0000 deadbeef 000102"); + + grpc_sopb_add_slice(&g_sopb, create_test_slice(4)); + verify_sopb(10, 0, 4, "000004 0000 deadbeef 00010203"); + + grpc_sopb_add_slice(&g_sopb, create_test_slice(3)); + grpc_sopb_add_slice(&g_sopb, create_test_slice(4)); + verify_sopb(10, 0, 7, "000007 0000 deadbeef 000102 00010203"); + + grpc_sopb_add_slice(&g_sopb, create_test_slice(0)); + grpc_sopb_add_slice(&g_sopb, create_test_slice(0)); + grpc_sopb_add_slice(&g_sopb, create_test_slice(0)); + grpc_sopb_add_slice(&g_sopb, create_test_slice(0)); + grpc_sopb_add_slice(&g_sopb, create_test_slice(3)); + verify_sopb(10, 0, 3, "000003 0000 deadbeef 000102"); + + verify_sopb(10, 1, 0, "000000 0001 deadbeef"); + + grpc_sopb_add_begin_message(&g_sopb, 255, 0); + verify_sopb(10, 0, 5, "000005 0000 deadbeef 00000000ff"); +} + +static void add_sopb_header(const char *key, const char *value) { + grpc_sopb_add_metadata(&g_sopb, + grpc_mdelem_from_strings(g_mdctx, key, value)); +} + +static void test_basic_headers() { + int i; + + add_sopb_header("a", "a"); + verify_sopb(0, 0, 0, "000005 0104 deadbeef 40 0161 0161"); + + add_sopb_header("a", "a"); + verify_sopb(0, 0, 0, "000001 0104 deadbeef be"); + + add_sopb_header("a", "a"); + verify_sopb(0, 0, 0, "000001 0104 deadbeef be"); + + add_sopb_header("a", "a"); + add_sopb_header("b", "c"); + verify_sopb(0, 0, 0, "000006 0104 deadbeef be 40 0162 0163"); + + add_sopb_header("a", "a"); + add_sopb_header("b", "c"); + verify_sopb(0, 0, 0, "000002 0104 deadbeef bf be"); + + add_sopb_header("a", "d"); + verify_sopb(0, 0, 0, "000004 0104 deadbeef 7f 00 0164"); + + /* flush out what's there to make a few values look very popular */ + for (i = 0; i < 350; i++) { + add_sopb_header("a", "a"); + add_sopb_header("b", "c"); + add_sopb_header("a", "d"); + verify_sopb(0, 0, 0, "000003 0104 deadbeef c0 bf be"); + } + + add_sopb_header("a", "a"); + add_sopb_header("k", "v"); + verify_sopb(0, 0, 0, "000006 0104 deadbeef c0 00 016b 0176"); + + add_sopb_header("a", "v"); + /* this could be 000004 0104 deadbeef 0f 30 0176 also */ + verify_sopb(0, 0, 0, "000004 0104 deadbeef 0f 2f 0176"); +} + +static void encode_int_to_str(int i, char *p) { + p[0] = 'a' + i % 26; + i /= 26; + GPR_ASSERT(i < 26); + p[1] = 'a' + i; + p[2] = 0; +} + +static void test_decode_table_overflow() { + int i; + char key[3], value[3]; + char expect[128]; + + for (i = 0; i < 114; i++) { + if (i > 0) { + add_sopb_header("aa", "ba"); + } + + encode_int_to_str(i, key); + encode_int_to_str(i + 1, value); + + if (i + 61 >= 127) { + sprintf(expect, "000009 0104 deadbeef ff%02x 40 02%02x%02x 02%02x%02x", + i + 61 - 127, key[0], key[1], value[0], value[1]); + } else if (i > 0) { + sprintf(expect, "000008 0104 deadbeef %02x 40 02%02x%02x 02%02x%02x", + 0x80 + 61 + i, key[0], key[1], value[0], value[1]); + } else { + sprintf(expect, "000007 0104 deadbeef 40 02%02x%02x 02%02x%02x", key[0], + key[1], value[0], value[1]); + } + + add_sopb_header(key, value); + verify_sopb(0, 0, 0, expect); + } + + /* if the above passes, then we must have just knocked this pair out of the + decoder stack, and so we'll be forced to re-encode it */ + add_sopb_header("aa", "ba"); + verify_sopb(0, 0, 0, "000007 0104 deadbeef 40 026161 026261"); +} + +static void randstr(char *p, int bufsz) { + int i; + int len = 1 + rand() % bufsz; + for (i = 0; i < len; i++) { + p[i] = 'a' + rand() % 26; + } + p[len] = 0; +} + +typedef struct { + char key[300]; + char value[300]; + int got_hdr; +} test_decode_random_header_state; + +static void chk_hdr(void *p, grpc_mdelem *el) { + test_decode_random_header_state *st = p; + GPR_ASSERT(0 == gpr_slice_str_cmp(el->key->slice, st->key)); + GPR_ASSERT(0 == gpr_slice_str_cmp(el->value->slice, st->value)); + st->got_hdr = 1; + grpc_mdelem_unref(el); +} + +static void test_decode_random_headers_inner(int max_len) { + int i; + test_decode_random_header_state st; + gpr_slice_buffer output; + gpr_slice merged; + grpc_chttp2_hpack_parser parser; + + grpc_chttp2_hpack_parser_init(&parser, g_mdctx); + + gpr_log(GPR_INFO, "max_len = %d", max_len); + + for (i = 0; i < 100000; i++) { + randstr(st.key, max_len); + randstr(st.value, max_len); + + add_sopb_header(st.key, st.value); + gpr_slice_buffer_init(&output); + GPR_ASSERT(0 == grpc_chttp2_encode_some(g_sopb.ops, &g_sopb.nops, 0, + &output, 0, 0xdeadbeef, + &g_compressor)); + merged = grpc_slice_merge(output.slices, output.count); + gpr_slice_buffer_destroy(&output); + + st.got_hdr = 0; + parser.on_header = chk_hdr; + parser.on_header_user_data = &st; + grpc_chttp2_hpack_parser_parse(&parser, GPR_SLICE_START_PTR(merged) + 9, + GPR_SLICE_END_PTR(merged)); + GPR_ASSERT(st.got_hdr); + + gpr_slice_unref(merged); + } + + grpc_chttp2_hpack_parser_destroy(&parser); +} + +#define DECL_TEST_DECODE_RANDOM_HEADERS(n) \ + static void test_decode_random_headers_##n() { \ + test_decode_random_headers_inner(n); \ + } \ + int keeps_formatting_correct_##n + +DECL_TEST_DECODE_RANDOM_HEADERS(1); +DECL_TEST_DECODE_RANDOM_HEADERS(2); +DECL_TEST_DECODE_RANDOM_HEADERS(3); +DECL_TEST_DECODE_RANDOM_HEADERS(5); +DECL_TEST_DECODE_RANDOM_HEADERS(8); +DECL_TEST_DECODE_RANDOM_HEADERS(13); +DECL_TEST_DECODE_RANDOM_HEADERS(21); +DECL_TEST_DECODE_RANDOM_HEADERS(34); +DECL_TEST_DECODE_RANDOM_HEADERS(55); +DECL_TEST_DECODE_RANDOM_HEADERS(89); +DECL_TEST_DECODE_RANDOM_HEADERS(144); + +static void run_test(void (*test)(), const char *name) { + gpr_log(GPR_INFO, "RUN TEST: %s", name); + g_mdctx = grpc_mdctx_create_with_seed(0); + grpc_chttp2_hpack_compressor_init(&g_compressor, g_mdctx); + grpc_sopb_init(&g_sopb); + test(); + grpc_chttp2_hpack_compressor_destroy(&g_compressor); + grpc_mdctx_orphan(g_mdctx); + grpc_sopb_destroy(&g_sopb); +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + TEST(test_small_data_framing); + TEST(test_basic_headers); + TEST(test_decode_table_overflow); + TEST(test_decode_random_headers_1); + TEST(test_decode_random_headers_2); + TEST(test_decode_random_headers_3); + TEST(test_decode_random_headers_5); + TEST(test_decode_random_headers_8); + TEST(test_decode_random_headers_13); + TEST(test_decode_random_headers_21); + TEST(test_decode_random_headers_34); + TEST(test_decode_random_headers_55); + TEST(test_decode_random_headers_89); + TEST(test_decode_random_headers_144); + return g_failure; +} |