diff options
Diffstat (limited to 'test/core/compression/message_compress_test.cc')
-rw-r--r-- | test/core/compression/message_compress_test.cc | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/test/core/compression/message_compress_test.cc b/test/core/compression/message_compress_test.cc new file mode 100644 index 0000000000..d642e056d8 --- /dev/null +++ b/test/core/compression/message_compress_test.cc @@ -0,0 +1,325 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "src/core/lib/compression/message_compress.h" + +#include <stdlib.h> +#include <string.h> + +#include <grpc/grpc.h> +#include <grpc/support/log.h> +#include <grpc/support/useful.h> + +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/support/murmur_hash.h" +#include "test/core/util/slice_splitter.h" +#include "test/core/util/test_config.h" + +typedef enum { ONE_A = 0, ONE_KB_A, ONE_MB_A, TEST_VALUE_COUNT } test_value; + +typedef enum { + SHOULD_NOT_COMPRESS, + SHOULD_COMPRESS, + MAYBE_COMPRESSES +} compressability; + +static void assert_passthrough(grpc_slice value, + grpc_compression_algorithm algorithm, + grpc_slice_split_mode uncompressed_split_mode, + grpc_slice_split_mode compressed_split_mode, + compressability compress_result_check) { + grpc_slice_buffer input; + grpc_slice_buffer compressed_raw; + grpc_slice_buffer compressed; + grpc_slice_buffer output; + grpc_slice final; + int was_compressed; + const char* algorithm_name; + + GPR_ASSERT(grpc_compression_algorithm_name(algorithm, &algorithm_name) != 0); + gpr_log(GPR_INFO, + "assert_passthrough: value_length=%" PRIuPTR + " value_hash=0x%08x " + "algorithm='%s' uncompressed_split='%s' compressed_split='%s'", + GRPC_SLICE_LENGTH(value), + gpr_murmur_hash3(GRPC_SLICE_START_PTR(value), + GRPC_SLICE_LENGTH(value), 0), + algorithm_name, grpc_slice_split_mode_name(uncompressed_split_mode), + grpc_slice_split_mode_name(compressed_split_mode)); + + grpc_slice_buffer_init(&input); + grpc_slice_buffer_init(&compressed_raw); + grpc_slice_buffer_init(&compressed); + grpc_slice_buffer_init(&output); + + grpc_split_slices_to_buffer(uncompressed_split_mode, &value, 1, &input); + + { + ExecCtx _local_exec_ctx; + was_compressed = grpc_msg_compress(algorithm, &input, &compressed_raw); + grpc_exec_ctx_finish(); + } + GPR_ASSERT(input.count > 0); + + switch (compress_result_check) { + case SHOULD_NOT_COMPRESS: + GPR_ASSERT(was_compressed == 0); + break; + case SHOULD_COMPRESS: + GPR_ASSERT(was_compressed == 1); + break; + case MAYBE_COMPRESSES: + /* no check */ + break; + } + + grpc_split_slice_buffer(compressed_split_mode, &compressed_raw, &compressed); + + { + ExecCtx _local_exec_ctx; + GPR_ASSERT(grpc_msg_decompress( + was_compressed ? algorithm : GRPC_COMPRESS_NONE, &compressed, &output)); + grpc_exec_ctx_finish(); + } + + final = grpc_slice_merge(output.slices, output.count); + GPR_ASSERT(grpc_slice_eq(value, final)); + + grpc_slice_buffer_destroy(&input); + grpc_slice_buffer_destroy(&compressed); + grpc_slice_buffer_destroy(&compressed_raw); + grpc_slice_buffer_destroy(&output); + grpc_slice_unref(final); +} + +static grpc_slice repeated(char c, size_t length) { + grpc_slice out = grpc_slice_malloc(length); + memset(GRPC_SLICE_START_PTR(out), c, length); + return out; +} + +static compressability get_compressability( + test_value id, grpc_compression_algorithm algorithm) { + if (algorithm == GRPC_COMPRESS_NONE) return SHOULD_NOT_COMPRESS; + switch (id) { + case ONE_A: + return SHOULD_NOT_COMPRESS; + case ONE_KB_A: + case ONE_MB_A: + return SHOULD_COMPRESS; + case TEST_VALUE_COUNT: + abort(); + break; + } + return MAYBE_COMPRESSES; +} + +static grpc_slice create_test_value(test_value id) { + switch (id) { + case ONE_A: + return grpc_slice_from_copied_string("a"); + case ONE_KB_A: + return repeated('a', 1024); + case ONE_MB_A: + return repeated('a', 1024 * 1024); + case TEST_VALUE_COUNT: + abort(); + break; + } + return grpc_slice_from_copied_string("bad value"); +} + +static void test_tiny_data_compress(void) { + grpc_slice_buffer input; + grpc_slice_buffer output; + + grpc_slice_buffer_init(&input); + grpc_slice_buffer_init(&output); + grpc_slice_buffer_add(&input, create_test_value(ONE_A)); + + for (int i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) { + if (i == GRPC_COMPRESS_NONE) continue; + ExecCtx _local_exec_ctx; + GPR_ASSERT(0 == + grpc_msg_compress(static_cast<grpc_compression_algorithm>(i), + &input, &output)); + grpc_exec_ctx_finish(); + GPR_ASSERT(1 == output.count); + } + + grpc_slice_buffer_destroy(&input); + grpc_slice_buffer_destroy(&output); +} + +static void test_bad_decompression_data_crc(void) { + grpc_slice_buffer input; + grpc_slice_buffer corrupted; + grpc_slice_buffer output; + size_t idx; + const uint32_t bad = 0xdeadbeef; + + grpc_slice_buffer_init(&input); + grpc_slice_buffer_init(&corrupted); + grpc_slice_buffer_init(&output); + grpc_slice_buffer_add(&input, create_test_value(ONE_MB_A)); + + ExecCtx _local_exec_ctx; + /* compress it */ + grpc_msg_compress(GRPC_COMPRESS_GZIP, &input, &corrupted); + /* corrupt the output by smashing the CRC */ + GPR_ASSERT(corrupted.count > 1); + GPR_ASSERT(GRPC_SLICE_LENGTH(corrupted.slices[1]) > 8); + idx = GRPC_SLICE_LENGTH(corrupted.slices[1]) - 8; + memcpy(GRPC_SLICE_START_PTR(corrupted.slices[1]) + idx, &bad, 4); + + /* try (and fail) to decompress the corrupted compresed buffer */ + GPR_ASSERT(0 == grpc_msg_decompress(GRPC_COMPRESS_GZIP, &corrupted, &output)); + grpc_exec_ctx_finish(); + + grpc_slice_buffer_destroy(&input); + grpc_slice_buffer_destroy(&corrupted); + grpc_slice_buffer_destroy(&output); +} + +static void test_bad_decompression_data_trailing_garbage(void) { + grpc_slice_buffer input; + grpc_slice_buffer output; + + grpc_slice_buffer_init(&input); + grpc_slice_buffer_init(&output); + /* append 0x99 to the end of an otherwise valid stream */ + grpc_slice_buffer_add( + &input, grpc_slice_from_copied_buffer( + "\x78\xda\x63\x60\x60\x60\x00\x00\x00\x04\x00\x01\x99", 13)); + + /* try (and fail) to decompress the invalid compresed buffer */ + ExecCtx _local_exec_ctx; + GPR_ASSERT(0 == grpc_msg_decompress(GRPC_COMPRESS_DEFLATE, &input, &output)); + grpc_exec_ctx_finish(); + + grpc_slice_buffer_destroy(&input); + grpc_slice_buffer_destroy(&output); +} + +static void test_bad_decompression_data_stream(void) { + grpc_slice_buffer input; + grpc_slice_buffer output; + + grpc_slice_buffer_init(&input); + grpc_slice_buffer_init(&output); + grpc_slice_buffer_add(&input, + grpc_slice_from_copied_buffer("\x78\xda\xff\xff", 4)); + + /* try (and fail) to decompress the invalid compresed buffer */ + ExecCtx _local_exec_ctx; + GPR_ASSERT(0 == grpc_msg_decompress(GRPC_COMPRESS_DEFLATE, &input, &output)); + grpc_exec_ctx_finish(); + + grpc_slice_buffer_destroy(&input); + grpc_slice_buffer_destroy(&output); +} + +static void test_bad_compression_algorithm(void) { + grpc_slice_buffer input; + grpc_slice_buffer output; + int was_compressed; + + grpc_slice_buffer_init(&input); + grpc_slice_buffer_init(&output); + grpc_slice_buffer_add( + &input, grpc_slice_from_copied_string("Never gonna give you up")); + + ExecCtx _local_exec_ctx; + was_compressed = + grpc_msg_compress(GRPC_COMPRESS_ALGORITHMS_COUNT, &input, &output); + GPR_ASSERT(0 == was_compressed); + + was_compressed = grpc_msg_compress(static_cast<grpc_compression_algorithm>( + GRPC_COMPRESS_ALGORITHMS_COUNT + 123), + &input, &output); + GPR_ASSERT(0 == was_compressed); + grpc_exec_ctx_finish(); + + grpc_slice_buffer_destroy(&input); + grpc_slice_buffer_destroy(&output); +} + +static void test_bad_decompression_algorithm(void) { + grpc_slice_buffer input; + grpc_slice_buffer output; + int was_decompressed; + + grpc_slice_buffer_init(&input); + grpc_slice_buffer_init(&output); + grpc_slice_buffer_add(&input, + grpc_slice_from_copied_string( + "I'm not really compressed but it doesn't matter")); + ExecCtx _local_exec_ctx; + was_decompressed = + grpc_msg_decompress(GRPC_COMPRESS_ALGORITHMS_COUNT, &input, &output); + GPR_ASSERT(0 == was_decompressed); + + was_decompressed = + grpc_msg_decompress(static_cast<grpc_compression_algorithm>( + GRPC_COMPRESS_ALGORITHMS_COUNT + 123), + &input, &output); + GPR_ASSERT(0 == was_decompressed); + grpc_exec_ctx_finish(); + + grpc_slice_buffer_destroy(&input); + grpc_slice_buffer_destroy(&output); +} + +int main(int argc, char** argv) { + unsigned i, j, k, m; + grpc_slice_split_mode uncompressed_split_modes[] = { + GRPC_SLICE_SPLIT_IDENTITY, GRPC_SLICE_SPLIT_ONE_BYTE}; + grpc_slice_split_mode compressed_split_modes[] = {GRPC_SLICE_SPLIT_MERGE_ALL, + GRPC_SLICE_SPLIT_IDENTITY, + GRPC_SLICE_SPLIT_ONE_BYTE}; + + grpc_test_init(argc, argv); + grpc_init(); + + for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) { + for (j = 0; j < GPR_ARRAY_SIZE(uncompressed_split_modes); j++) { + for (k = 0; k < GPR_ARRAY_SIZE(compressed_split_modes); k++) { + for (m = 0; m < TEST_VALUE_COUNT; m++) { + grpc_slice slice = create_test_value(static_cast<test_value>(m)); + assert_passthrough( + slice, static_cast<grpc_compression_algorithm>(i), + static_cast<grpc_slice_split_mode>(j), + static_cast<grpc_slice_split_mode>(k), + get_compressability(static_cast<test_value>(m), + static_cast<grpc_compression_algorithm>(i))); + grpc_slice_unref(slice); + } + } + } + } + + test_tiny_data_compress(); + test_bad_decompression_data_crc(); + test_bad_decompression_data_stream(); + test_bad_decompression_data_trailing_garbage(); + test_bad_compression_algorithm(); + test_bad_decompression_algorithm(); + grpc_shutdown(); + + return 0; +} |