|
3 | 3 | #include <fluent-bit/flb_info.h>
|
4 | 4 | #include <fluent-bit/flb_mem.h>
|
5 | 5 | #include <fluent-bit/flb_zstd.h>
|
| 6 | +#include <fluent-bit/flb_compression.h> |
6 | 7 | #include "flb_tests_internal.h"
|
7 | 8 |
|
8 | 9 | /* try a small string */
|
@@ -163,12 +164,167 @@ static void test_decompress_unknown_size()
|
163 | 164 | flb_free(decompressed_data);
|
164 | 165 | }
|
165 | 166 |
|
| 167 | +static void append_to_context(struct flb_decompression_context *ctx, const void *data, size_t size) |
| 168 | +{ |
| 169 | + uint8_t *append_ptr; |
| 170 | + size_t available_space; |
| 171 | + |
| 172 | + available_space = flb_decompression_context_get_available_space(ctx); |
| 173 | + |
| 174 | + if (size > available_space) { |
| 175 | + size_t required_size = ctx->input_buffer_length + size; |
| 176 | + flb_decompression_context_resize_buffer(ctx, required_size); |
| 177 | + } |
| 178 | + |
| 179 | + /* Get pointer to the write location */ |
| 180 | + append_ptr = flb_decompression_context_get_append_buffer(ctx); |
| 181 | + TEST_CHECK(append_ptr != NULL); |
| 182 | + |
| 183 | + /* Copy the data */ |
| 184 | + memcpy(append_ptr, data, size); |
| 185 | + |
| 186 | + ctx->input_buffer_length += size; |
| 187 | +} |
| 188 | + |
| 189 | +static void *compress_with_checksum(const void *original_data, size_t original_len, |
| 190 | + size_t *compressed_len) |
| 191 | +{ |
| 192 | + ZSTD_CCtx* cctx; |
| 193 | + void *compressed_buffer; |
| 194 | + size_t bound; |
| 195 | + size_t ret; |
| 196 | + |
| 197 | + /* Create a compression context */ |
| 198 | + cctx = ZSTD_createCCtx(); |
| 199 | + TEST_CHECK(cctx != NULL); |
| 200 | + |
| 201 | + /* |
| 202 | + * THIS IS THE KEY: Explicitly enable content checksums in the frame. |
| 203 | + */ |
| 204 | + ret = ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1); |
| 205 | + TEST_CHECK(!ZSTD_isError(ret)); |
| 206 | + |
| 207 | + /* Compress the data */ |
| 208 | + bound = ZSTD_compressBound(original_len); |
| 209 | + compressed_buffer = flb_malloc(bound); |
| 210 | + TEST_CHECK(compressed_buffer != NULL); |
| 211 | + |
| 212 | + *compressed_len = ZSTD_compress2(cctx, |
| 213 | + compressed_buffer, bound, |
| 214 | + original_data, original_len); |
| 215 | + |
| 216 | + TEST_CHECK(!ZSTD_isError(*compressed_len)); |
| 217 | + |
| 218 | + ZSTD_freeCCtx(cctx); |
| 219 | + |
| 220 | + return compressed_buffer; |
| 221 | +} |
| 222 | + |
| 223 | +void test_zstd_streaming_decompress_multi_chunk(void) |
| 224 | +{ |
| 225 | + struct flb_decompression_context *ctx; |
| 226 | + char *output_buf; |
| 227 | + size_t output_len; |
| 228 | + size_t total_written = 0; |
| 229 | + int ret; |
| 230 | + size_t chunk1_size = 0; |
| 231 | + size_t chunk2_size = 0; |
| 232 | + size_t chunk3_size = 0; |
| 233 | + char *original_text = "zstd streaming is a feature that must be tested with multiple, uneven chunks!"; |
| 234 | + size_t original_len; |
| 235 | + void *compressed_buf = NULL; |
| 236 | + size_t compressed_len = 0; |
| 237 | + |
| 238 | + original_len = strlen(original_text); |
| 239 | + compressed_buf = compress_with_checksum(original_text, original_len, &compressed_len); |
| 240 | + TEST_CHECK(compressed_buf != NULL); |
| 241 | + |
| 242 | + ctx = flb_decompression_context_create(FLB_COMPRESSION_ALGORITHM_ZSTD, compressed_len); |
| 243 | + TEST_CHECK(ctx != NULL); |
| 244 | + output_buf = flb_malloc(original_len + 1); |
| 245 | + |
| 246 | + chunk1_size = compressed_len / 3; |
| 247 | + chunk2_size = compressed_len / 2; |
| 248 | + chunk3_size = compressed_len - chunk1_size - chunk2_size; |
| 249 | + |
| 250 | + append_to_context(ctx, compressed_buf, chunk1_size); |
| 251 | + output_len = original_len; |
| 252 | + ret = flb_decompress(ctx, output_buf, &output_len); |
| 253 | + TEST_CHECK(ret == FLB_DECOMPRESSOR_SUCCESS); |
| 254 | + total_written += output_len; |
| 255 | + |
| 256 | + append_to_context(ctx, (char *)compressed_buf + chunk1_size, chunk2_size); |
| 257 | + output_len = original_len - total_written; |
| 258 | + ret = flb_decompress(ctx, output_buf + total_written, &output_len); |
| 259 | + TEST_CHECK(ret == FLB_DECOMPRESSOR_SUCCESS); |
| 260 | + total_written += output_len; |
| 261 | + |
| 262 | + append_to_context(ctx, (char *)compressed_buf + chunk1_size + chunk2_size, chunk3_size); |
| 263 | + output_len = original_len - total_written; |
| 264 | + ret = flb_decompress(ctx, output_buf + total_written, &output_len); |
| 265 | + TEST_CHECK(ret == FLB_DECOMPRESSOR_SUCCESS); |
| 266 | + total_written += output_len; |
| 267 | + |
| 268 | + TEST_CHECK(total_written == original_len); |
| 269 | + TEST_CHECK(memcmp(original_text, output_buf, original_len) == 0); |
| 270 | + |
| 271 | + flb_free(compressed_buf); |
| 272 | + flb_free(output_buf); |
| 273 | + flb_decompression_context_destroy(ctx); |
| 274 | +} |
| 275 | + |
| 276 | +/* In tests/internal/zstd.c */ |
| 277 | + |
| 278 | +void test_zstd_streaming_decompress_corrupted_data(void) |
| 279 | +{ |
| 280 | + struct flb_decompression_context *ctx; |
| 281 | + char *output_buf; |
| 282 | + size_t output_len; |
| 283 | + int ret; |
| 284 | + char *original_text = "this test ensures corrupted data with a checksum fails"; |
| 285 | + size_t original_len = strlen(original_text); |
| 286 | + void *compressed_buf = NULL; |
| 287 | + size_t compressed_len = 0; |
| 288 | + char *corrupted_input; |
| 289 | + |
| 290 | + compressed_buf = compress_with_checksum(original_text, original_len, &compressed_len); |
| 291 | + TEST_CHECK(compressed_buf != NULL); |
| 292 | + |
| 293 | + ctx = flb_decompression_context_create(FLB_COMPRESSION_ALGORITHM_ZSTD, compressed_len); |
| 294 | + TEST_CHECK(ctx != NULL); |
| 295 | + |
| 296 | + /* Create a corrupted copy of the input */ |
| 297 | + corrupted_input = flb_malloc(compressed_len); |
| 298 | + TEST_CHECK(corrupted_input != NULL); |
| 299 | + memcpy(corrupted_input, compressed_buf, compressed_len); |
| 300 | + /* Corrupt a byte in the middle */ |
| 301 | + corrupted_input[compressed_len / 2]++; |
| 302 | + |
| 303 | + append_to_context(ctx, corrupted_input, compressed_len); |
| 304 | + |
| 305 | + output_buf = flb_malloc(original_len + 1); |
| 306 | + output_len = original_len; |
| 307 | + |
| 308 | + ret = flb_decompress(ctx, output_buf, &output_len); |
| 309 | + |
| 310 | + TEST_CHECK(ret == FLB_DECOMPRESSOR_FAILURE); |
| 311 | + TEST_CHECK(ctx->state == FLB_DECOMPRESSOR_STATE_FAILED); |
| 312 | + |
| 313 | + flb_free(compressed_buf); |
| 314 | + flb_free(corrupted_input); |
| 315 | + flb_free(output_buf); |
| 316 | + flb_decompression_context_destroy(ctx); |
| 317 | +} |
| 318 | + |
| 319 | + |
166 | 320 | TEST_LIST = {
|
167 | 321 | { "compress_small_string", test_compress_small_string },
|
168 | 322 | { "decompress_small_string", test_decompress_small_string },
|
169 | 323 | { "compress_empty_input", test_compress_empty_input },
|
170 | 324 | { "decompress_invalid_data", test_decompress_invalid_data },
|
171 | 325 | { "compress_decompress_large_data", test_compress_decompress_large_data },
|
172 | 326 | { "decompress_unknown_size", test_decompress_unknown_size },
|
| 327 | + { "streaming_decompress_multi_chunk", test_zstd_streaming_decompress_multi_chunk }, |
| 328 | + { "streaming_decompress_corrupted_data", test_zstd_streaming_decompress_corrupted_data }, |
173 | 329 | { NULL, NULL }
|
174 | 330 | };
|
0 commit comments