diff --git a/plugins/out_azure_blob/azure_blob.c b/plugins/out_azure_blob/azure_blob.c index a650809c4d4..5e6905863e0 100644 --- a/plugins/out_azure_blob/azure_blob.c +++ b/plugins/out_azure_blob/azure_blob.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -136,7 +138,7 @@ static int construct_request_buffer(struct flb_azure_blob *ctx, flb_sds_t new_da } body = buffered_data = tmp; memcpy(body + buffer_size, new_data, flb_sds_len(new_data)); - if (ctx->compress_gzip == FLB_FALSE){ + if (ctx->compression == FLB_COMPRESSION_ALGORITHM_NONE) { body[body_size] = '\0'; } } @@ -149,6 +151,38 @@ static int construct_request_buffer(struct flb_azure_blob *ctx, flb_sds_t new_da return 0; } +/* + * Compress a payload using the configured algorithm. Returns 0 on success and + * negative on failure so callers can gracefully fall back to sending the raw + * payload. + */ +static int azure_blob_compress_payload(int algorithm, + void *in_data, size_t in_len, + void **out_data, size_t *out_len) +{ + if (algorithm == FLB_COMPRESSION_ALGORITHM_GZIP) { + return flb_gzip_compress(in_data, in_len, out_data, out_len); + } + else if (algorithm == FLB_COMPRESSION_ALGORITHM_ZSTD) { + return flb_zstd_compress(in_data, in_len, out_data, out_len); + } + + return -1; +} + +/* Map a compression algorithm to its human-friendly label for logs. */ +static const char *azure_blob_compression_name(int algorithm) +{ + if (algorithm == FLB_COMPRESSION_ALGORITHM_GZIP) { + return "gzip"; + } + else if (algorithm == FLB_COMPRESSION_ALGORITHM_ZSTD) { + return "zstd"; + } + + return "unknown"; +} + void generate_random_string_blob(char *str, size_t length) { const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; @@ -323,6 +357,37 @@ static int delete_blob(struct flb_azure_blob *ctx, char *name) return FLB_OK; } +int azb_select_compression_strategy(struct flb_azure_blob *ctx, + int *compression_algorithm, + int *prefer_blob_compression) +{ + int algorithm = FLB_COMPRESSION_ALGORITHM_NONE; + int prefer_blob = FLB_FALSE; + + if (ctx->compress_blob == FLB_TRUE) { + prefer_blob = FLB_TRUE; + if (ctx->compression != FLB_COMPRESSION_ALGORITHM_NONE) { + algorithm = ctx->compression; + } + else { + algorithm = FLB_COMPRESSION_ALGORITHM_GZIP; + } + } + else if (ctx->compression != FLB_COMPRESSION_ALGORITHM_NONE) { + algorithm = ctx->compression; + } + + if (compression_algorithm != NULL) { + *compression_algorithm = algorithm; + } + + if (prefer_blob_compression != NULL) { + *prefer_blob_compression = prefer_blob; + } + + return 0; +} + static int http_send_blob(struct flb_config *config, struct flb_azure_blob *ctx, flb_sds_t ref_name, flb_sds_t uri, @@ -332,8 +397,13 @@ static int http_send_blob(struct flb_config *config, struct flb_azure_blob *ctx, { int ret; int compressed = FLB_FALSE; - int content_encoding = FLB_FALSE; - int content_type = FLB_FALSE; + int content_encoding = AZURE_BLOB_CE_NONE; + int content_type = AZURE_BLOB_CT_NONE; + int compression_algorithm = FLB_COMPRESSION_ALGORITHM_NONE; + int network_compression_algorithm = ctx->compression; + int network_compression_applied = FLB_FALSE; + int blob_compression_applied = FLB_FALSE; + int prefer_blob_compression = FLB_FALSE; size_t b_sent; void *payload_buf; size_t payload_size; @@ -358,27 +428,59 @@ static int http_send_blob(struct flb_config *config, struct flb_azure_blob *ctx, payload_buf = data; payload_size = bytes; + /* Determine compression algorithm */ + azb_select_compression_strategy(ctx, &compression_algorithm, + &prefer_blob_compression); + /* Handle compression requests */ - if (ctx->compress_gzip == FLB_TRUE || ctx->compress_blob == FLB_TRUE) { - ret = flb_gzip_compress((void *) data, bytes, &payload_buf, &payload_size); + if (compression_algorithm != FLB_COMPRESSION_ALGORITHM_NONE) { + ret = azure_blob_compress_payload(compression_algorithm, + (void *) data, bytes, + &payload_buf, &payload_size); if (ret == 0) { compressed = FLB_TRUE; + if (prefer_blob_compression == FLB_TRUE) { + blob_compression_applied = FLB_TRUE; + } + else if (network_compression_algorithm != FLB_COMPRESSION_ALGORITHM_NONE && + compression_algorithm == network_compression_algorithm) { + network_compression_applied = FLB_TRUE; + } } else { + const char *alg_name; + + alg_name = azure_blob_compression_name(compression_algorithm); flb_plg_warn(ctx->ins, - "cannot gzip payload, disabling compression"); + "cannot %s payload, disabling compression", + alg_name); payload_buf = data; payload_size = bytes; + compression_algorithm = FLB_COMPRESSION_ALGORITHM_NONE; } } /* set http header flags */ - if (ctx->compress_blob == FLB_TRUE) { + /* Blob compression takes precedence over network compression since we + * cannot advertise both a compressed blob content type and a transport + * content-encoding at the same time. */ + if (blob_compression_applied == FLB_TRUE) { content_encoding = AZURE_BLOB_CE_NONE; - content_type = AZURE_BLOB_CT_GZIP; + + if (compression_algorithm == FLB_COMPRESSION_ALGORITHM_ZSTD) { + content_type = AZURE_BLOB_CT_ZSTD; + } + else { + content_type = AZURE_BLOB_CT_GZIP; + } } - else if (compressed == FLB_TRUE) { - content_encoding = AZURE_BLOB_CE_GZIP; + else if (network_compression_applied == FLB_TRUE) { + if (network_compression_algorithm == FLB_COMPRESSION_ALGORITHM_GZIP) { + content_encoding = AZURE_BLOB_CE_GZIP; + } + else if (network_compression_algorithm == FLB_COMPRESSION_ALGORITHM_ZSTD) { + content_encoding = AZURE_BLOB_CE_ZSTD; + } content_type = AZURE_BLOB_CT_JSON; } @@ -1783,14 +1885,15 @@ static struct flb_config_map config_map[] = { { FLB_CONFIG_MAP_STR, "compress", NULL, 0, FLB_FALSE, 0, - "Set payload compression in network transfer. Option available is 'gzip'" + "Set payload compression in network transfer. Options: 'gzip', 'zstd'" }, { FLB_CONFIG_MAP_BOOL, "compress_blob", "false", 0, FLB_TRUE, offsetof(struct flb_azure_blob, compress_blob), - "Enable block blob GZIP compression in the final blob file. This option is " - "not compatible with 'appendblob' block type" + "Enable block blob compression in the final blob file (defaults to gzip, " + "uses the 'compress' codec when set). This option is not compatible with " + "'appendblob' block type" }, { diff --git a/plugins/out_azure_blob/azure_blob.h b/plugins/out_azure_blob/azure_blob.h index 8699dda54f8..2ca403663fe 100644 --- a/plugins/out_azure_blob/azure_blob.h +++ b/plugins/out_azure_blob/azure_blob.h @@ -30,11 +30,13 @@ #define AZURE_BLOB_CT_NONE 0 #define AZURE_BLOB_CT_JSON 1 /* application/json */ #define AZURE_BLOB_CT_GZIP 2 /* application/gzip */ +#define AZURE_BLOB_CT_ZSTD 3 /* application/zstd */ /* Content-Encoding */ #define AZURE_BLOB_CE "Content-Encoding" #define AZURE_BLOB_CE_NONE 0 #define AZURE_BLOB_CE_GZIP 1 /* gzip */ +#define AZURE_BLOB_CE_ZSTD 2 /* zstd */ /* service endpoint */ #define AZURE_ENDPOINT_PREFIX ".blob.core.windows.net" @@ -54,7 +56,7 @@ struct flb_azure_blob { int auto_create_container; int emulator_mode; - int compress_gzip; + int compression; int compress_blob; flb_sds_t account_name; flb_sds_t container_name; @@ -166,4 +168,8 @@ struct flb_azure_blob { struct flb_config *config; }; +int azb_select_compression_strategy(struct flb_azure_blob *ctx, + int *compression_algorithm, + int *prefer_blob_compression); + #endif diff --git a/plugins/out_azure_blob/azure_blob_blockblob.c b/plugins/out_azure_blob/azure_blob_blockblob.c index 860401b2623..96b47d860b8 100644 --- a/plugins/out_azure_blob/azure_blob_blockblob.c +++ b/plugins/out_azure_blob/azure_blob_blockblob.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -31,6 +32,19 @@ #include "azure_blob_uri.h" #include "azure_blob_http.h" +static const char *azb_blob_extension(struct flb_azure_blob *ctx) +{ + if (ctx->compress_blob != FLB_TRUE) { + return ""; + } + + if (ctx->compression == FLB_COMPRESSION_ALGORITHM_ZSTD) { + return ".zst"; + } + + return ".gz"; +} + flb_sds_t azb_block_blob_blocklist_uri(struct flb_azure_blob *ctx, char *name) { flb_sds_t uri; @@ -60,7 +74,7 @@ flb_sds_t azb_block_blob_uri(struct flb_azure_blob *ctx, char *name, { int len; flb_sds_t uri; - char *ext; + const char *ext; char *encoded_blockid; len = strlen(blockid); @@ -75,12 +89,7 @@ flb_sds_t azb_block_blob_uri(struct flb_azure_blob *ctx, char *name, return NULL; } - if (ctx->compress_blob == FLB_TRUE) { - ext = ".gz"; - } - else { - ext = ""; - } + ext = azb_blob_extension(ctx); if (ctx->path) { if (ms > 0) { @@ -114,7 +123,7 @@ flb_sds_t azb_block_blob_uri(struct flb_azure_blob *ctx, char *name, flb_sds_t azb_block_blob_uri_commit(struct flb_azure_blob *ctx, char *tag, uint64_t ms, char *str) { - char *ext; + const char *ext; flb_sds_t uri; uri = azb_uri_container(ctx); @@ -122,12 +131,7 @@ flb_sds_t azb_block_blob_uri_commit(struct flb_azure_blob *ctx, return NULL; } - if (ctx->compress_blob == FLB_TRUE) { - ext = ".gz"; - } - else { - ext = ""; - } + ext = azb_blob_extension(ctx); if (ctx->path) { flb_sds_printf(&uri, "/%s/%s.%s.%" PRIu64 "%s?comp=blocklist", ctx->path, tag, str, diff --git a/plugins/out_azure_blob/azure_blob_conf.c b/plugins/out_azure_blob/azure_blob_conf.c index ea883a01852..3a01b9018d4 100644 --- a/plugins/out_azure_blob/azure_blob_conf.c +++ b/plugins/out_azure_blob/azure_blob_conf.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "azure_blob.h" #include "azure_blob_conf.h" @@ -655,12 +656,19 @@ struct flb_azure_blob *flb_azure_blob_conf_create(struct flb_output_instance *in return NULL; } - /* Compress (gzip) */ + /* Compress payload over the wire */ tmp = (char *) flb_output_get_property("compress", ins); - ctx->compress_gzip = FLB_FALSE; + ctx->compression = FLB_COMPRESSION_ALGORITHM_NONE; if (tmp) { if (strcasecmp(tmp, "gzip") == 0) { - ctx->compress_gzip = FLB_TRUE; + ctx->compression = FLB_COMPRESSION_ALGORITHM_GZIP; + } + else if (strcasecmp(tmp, "zstd") == 0) { + ctx->compression = FLB_COMPRESSION_ALGORITHM_ZSTD; + } + else { + flb_plg_error(ctx->ins, "invalid compress value '%s' (supported: gzip, zstd)", tmp); + return NULL; } } diff --git a/plugins/out_azure_blob/azure_blob_http.c b/plugins/out_azure_blob/azure_blob_http.c index c5d26554adb..28427097c0e 100644 --- a/plugins/out_azure_blob/azure_blob_http.c +++ b/plugins/out_azure_blob/azure_blob_http.c @@ -193,6 +193,9 @@ flb_sds_t azb_http_canonical_request(struct flb_azure_blob *ctx, if (content_encoding == AZURE_BLOB_CE_GZIP) { encoding = "gzip"; } + else if (content_encoding == AZURE_BLOB_CE_ZSTD) { + encoding = "zstd"; + } else { encoding = ""; } @@ -223,6 +226,9 @@ flb_sds_t azb_http_canonical_request(struct flb_azure_blob *ctx, else if (content_type == AZURE_BLOB_CT_GZIP) { ctype = "application/gzip"; } + else if (content_type == AZURE_BLOB_CT_ZSTD) { + ctype = "application/zstd"; + } flb_sds_printf(&can_req, "\n" /* Content-MD5 */ @@ -315,12 +321,22 @@ int azb_http_client_setup(struct flb_azure_blob *ctx, struct flb_http_client *c, AZURE_BLOB_CT, sizeof(AZURE_BLOB_CT) - 1, "application/gzip", 16); } + else if (content_type == AZURE_BLOB_CT_ZSTD) { + flb_http_add_header(c, + AZURE_BLOB_CT, sizeof(AZURE_BLOB_CT) - 1, + "application/zstd", 16); + } if (content_encoding == AZURE_BLOB_CE_GZIP) { flb_http_add_header(c, AZURE_BLOB_CE, sizeof(AZURE_BLOB_CE) - 1, "gzip", 4); } + else if (content_encoding == AZURE_BLOB_CE_ZSTD) { + flb_http_add_header(c, + AZURE_BLOB_CE, sizeof(AZURE_BLOB_CE) - 1, + "zstd", 4); + } /* Azure header: x-ms-blob-type */ if (blob_type == FLB_TRUE) { diff --git a/plugins/out_azure_blob/azure_blob_http.h b/plugins/out_azure_blob/azure_blob_http.h index d617d433bf0..1a3b48692e3 100644 --- a/plugins/out_azure_blob/azure_blob_http.h +++ b/plugins/out_azure_blob/azure_blob_http.h @@ -31,6 +31,7 @@ int azb_http_client_setup(struct flb_azure_blob *ctx, struct flb_http_client *c, flb_sds_t azb_http_canonical_request(struct flb_azure_blob *ctx, struct flb_http_client *c, ssize_t content_length, - int content_type); + int content_type, + int content_encoding); #endif diff --git a/tests/runtime/CMakeLists.txt b/tests/runtime/CMakeLists.txt index dd76c16faee..a39a68b9393 100644 --- a/tests/runtime/CMakeLists.txt +++ b/tests/runtime/CMakeLists.txt @@ -204,6 +204,7 @@ if(FLB_IN_LIB) FLB_RT_TEST(FLB_OUT_LIB "core_routes.c") FLB_RT_TEST(FLB_OUT_LIB "config_map_opts.c") FLB_RT_TEST(FLB_OUT_COUNTER "out_counter.c") + FLB_RT_TEST(FLB_OUT_AZURE_BLOB "out_azure_blob_compression.c") FLB_RT_TEST(FLB_OUT_AZURE_KUSTO "out_azure_kusto.c") FLB_RT_TEST(FLB_OUT_DATADOG "out_datadog.c") FLB_RT_TEST(FLB_OUT_SKYWALKING "out_skywalking.c") diff --git a/tests/runtime/out_azure_blob_compression.c b/tests/runtime/out_azure_blob_compression.c new file mode 100644 index 00000000000..684eae9ace4 --- /dev/null +++ b/tests/runtime/out_azure_blob_compression.c @@ -0,0 +1,346 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2024 The Fluent Bit 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 + +#include +#include +#include +#include +#include +#include +#include + +#include "flb_tests_runtime.h" + +#include "../../plugins/out_azure_blob/azure_blob.h" +#include "../../plugins/out_azure_blob/azure_blob_blockblob.h" +#include "../../plugins/out_azure_blob/azure_blob_http.h" + +struct azure_blob_fixture { + struct flb_config *config; + struct flb_upstream *upstream; + struct flb_connection *connection; +}; + +static int azure_blob_fixture_init(struct azure_blob_fixture *fixture) +{ + memset(fixture, 0, sizeof(*fixture)); + + fixture->config = flb_config_init(); + if (!TEST_CHECK(fixture->config != NULL)) { + TEST_MSG("flb_config_init failed"); + return -1; + } + + fixture->upstream = flb_upstream_create(fixture->config, "127.0.0.1", + 80, FLB_IO_TCP, NULL); + if (!TEST_CHECK(fixture->upstream != NULL)) { + TEST_MSG("flb_upstream_create failed"); + flb_config_exit(fixture->config); + fixture->config = NULL; + return -1; + } + + fixture->connection = flb_calloc(1, sizeof(struct flb_connection)); + if (!TEST_CHECK(fixture->connection != NULL)) { + flb_errno(); + TEST_MSG("flb_calloc(flb_connection) failed"); + flb_upstream_destroy(fixture->upstream); + fixture->upstream = NULL; + flb_config_exit(fixture->config); + fixture->config = NULL; + return -1; + } + + fixture->connection->upstream = fixture->upstream; + return 0; +} + +static void azure_blob_fixture_destroy(struct azure_blob_fixture *fixture) +{ + if (fixture->connection != NULL) { + flb_free(fixture->connection); + } + + if (fixture->upstream != NULL) { + flb_upstream_destroy(fixture->upstream); + } + + if (fixture->config != NULL) { + flb_config_exit(fixture->config); + } +} + +static int azure_blob_ctx_init(struct flb_azure_blob *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->base_uri = flb_sds_create("/"); + if (!TEST_CHECK(ctx->base_uri != NULL)) { + TEST_MSG("flb_sds_create failed for base_uri"); + return -1; + } + ctx->container_name = flb_sds_create("container"); + if (!TEST_CHECK(ctx->container_name != NULL)) { + TEST_MSG("flb_sds_create failed for container_name"); + flb_sds_destroy(ctx->base_uri); + ctx->base_uri = NULL; + return -1; + } + ctx->btype = AZURE_BLOB_BLOCKBLOB; + ctx->atype = AZURE_BLOB_AUTH_KEY; + + return 0; +} + +static void azure_blob_ctx_destroy(struct flb_azure_blob *ctx) +{ + if (ctx->base_uri != NULL) { + flb_sds_destroy(ctx->base_uri); + } + + if (ctx->container_name != NULL) { + flb_sds_destroy(ctx->container_name); + } +} + +static void test_block_blob_extension_zstd() +{ + struct flb_azure_blob ctx; + flb_sds_t uri; + int ret; + + ret = azure_blob_ctx_init(&ctx); + if (ret != 0) { + return; + } + ctx.compress_blob = FLB_TRUE; + ctx.compression = FLB_COMPRESSION_ALGORITHM_ZSTD; + + uri = azb_block_blob_uri(&ctx, "file", "block", 123, "rand"); + TEST_CHECK(uri != NULL); + TEST_CHECK(strstr(uri, ".zst?blockid=") != NULL); + + flb_sds_destroy(uri); + azure_blob_ctx_destroy(&ctx); +} + +static void test_block_blob_extension_gzip_default() +{ + struct flb_azure_blob ctx; + flb_sds_t uri; + int ret; + + ret = azure_blob_ctx_init(&ctx); + if (ret != 0) { + return; + } + ctx.compress_blob = FLB_TRUE; + ctx.compression = FLB_COMPRESSION_ALGORITHM_NONE; + + /* When no explicit algorithm is configured, gzip remains the + * fallback to preserve legacy behavior. */ + + uri = azb_block_blob_uri(&ctx, "file", "block", 123, "rand"); + TEST_CHECK(uri != NULL); + TEST_CHECK(strstr(uri, ".gz?blockid=") != NULL); + + flb_sds_destroy(uri); + azure_blob_ctx_destroy(&ctx); +} + +static void test_block_blob_extension_disabled() +{ + struct flb_azure_blob ctx; + flb_sds_t uri; + int ret; + + ret = azure_blob_ctx_init(&ctx); + if (ret != 0) { + return; + } + ctx.compress_blob = FLB_FALSE; + ctx.compression = FLB_COMPRESSION_ALGORITHM_ZSTD; + + uri = azb_block_blob_uri(&ctx, "file", "block", 123, "rand"); + TEST_CHECK(uri != NULL); + TEST_CHECK(strstr(uri, ".gz?blockid=") == NULL); + TEST_CHECK(strstr(uri, ".zst?blockid=") == NULL); + + flb_sds_destroy(uri); + azure_blob_ctx_destroy(&ctx); +} + +static void test_http_headers_zstd_encoding() +{ + struct azure_blob_fixture fixture; + struct flb_http_client *client; + struct flb_azure_blob ctx; + struct flb_output_instance ins; + flb_sds_t header; + int ret; + + ret = azure_blob_fixture_init(&fixture); + if (!TEST_CHECK(ret == 0)) { + return; + } + + client = flb_http_client(fixture.connection, FLB_HTTP_PUT, "/resource", + NULL, 0, "localhost", 80, NULL, 0); + TEST_CHECK(client != NULL); + if (client == NULL) { + azure_blob_fixture_destroy(&fixture); + return; + } + + memset(&ins, 0, sizeof(ins)); + ret = azure_blob_ctx_init(&ctx); + if (ret != 0) { + flb_http_client_destroy(client); + azure_blob_fixture_destroy(&fixture); + return; + } + ctx.ins = &ins; + ctx.atype = AZURE_BLOB_AUTH_SAS; + + ret = azb_http_client_setup(&ctx, client, 1, FLB_FALSE, + AZURE_BLOB_CT_JSON, + AZURE_BLOB_CE_ZSTD); + TEST_CHECK(ret == 0); + + header = flb_http_get_header(client, "Content-Encoding", 16); + TEST_CHECK(header != NULL); + if (header != NULL) { + TEST_CHECK(strcmp(header, "zstd") == 0); + flb_sds_destroy(header); + } + + header = flb_http_get_header(client, "Content-Type", 12); + TEST_CHECK(header != NULL); + if (header != NULL) { + TEST_CHECK(strcmp(header, "application/json") == 0); + flb_sds_destroy(header); + } + + flb_http_client_destroy(client); + azure_blob_ctx_destroy(&ctx); + azure_blob_fixture_destroy(&fixture); +} + +static void test_http_headers_zstd_content_type() +{ + struct azure_blob_fixture fixture; + struct flb_http_client *client; + struct flb_azure_blob ctx; + struct flb_output_instance ins; + flb_sds_t header; + int ret; + + ret = azure_blob_fixture_init(&fixture); + if (!TEST_CHECK(ret == 0)) { + return; + } + + client = flb_http_client(fixture.connection, FLB_HTTP_PUT, "/resource", + NULL, 0, "localhost", 80, NULL, 0); + TEST_CHECK(client != NULL); + if (client == NULL) { + azure_blob_fixture_destroy(&fixture); + return; + } + + memset(&ins, 0, sizeof(ins)); + ret = azure_blob_ctx_init(&ctx); + if (ret != 0) { + flb_http_client_destroy(client); + azure_blob_fixture_destroy(&fixture); + return; + } + ctx.ins = &ins; + ctx.atype = AZURE_BLOB_AUTH_SAS; + + ret = azb_http_client_setup(&ctx, client, 1, FLB_FALSE, + AZURE_BLOB_CT_ZSTD, + AZURE_BLOB_CE_NONE); + TEST_CHECK(ret == 0); + + header = flb_http_get_header(client, "Content-Type", 12); + TEST_CHECK(header != NULL); + if (header != NULL) { + TEST_CHECK(strcmp(header, "application/zstd") == 0); + flb_sds_destroy(header); + } + + flb_http_client_destroy(client); + azure_blob_ctx_destroy(&ctx); + azure_blob_fixture_destroy(&fixture); +} + +static void test_compression_strategy_precedence() +{ + struct flb_azure_blob ctx; + int ret; + int algorithm; + int prefer_blob; + + ret = azure_blob_ctx_init(&ctx); + if (ret != 0) { + return; + } + + ctx.compress_blob = FLB_TRUE; + ctx.compression = FLB_COMPRESSION_ALGORITHM_ZSTD; + ret = azb_select_compression_strategy(&ctx, &algorithm, &prefer_blob); + TEST_CHECK(ret == 0); + TEST_CHECK(algorithm == FLB_COMPRESSION_ALGORITHM_ZSTD); + TEST_CHECK(prefer_blob == FLB_TRUE); + + ctx.compress_blob = FLB_TRUE; + ctx.compression = FLB_COMPRESSION_ALGORITHM_NONE; + ret = azb_select_compression_strategy(&ctx, &algorithm, &prefer_blob); + TEST_CHECK(ret == 0); + TEST_CHECK(algorithm == FLB_COMPRESSION_ALGORITHM_GZIP); + TEST_CHECK(prefer_blob == FLB_TRUE); + + ctx.compress_blob = FLB_FALSE; + ctx.compression = FLB_COMPRESSION_ALGORITHM_ZSTD; + ret = azb_select_compression_strategy(&ctx, &algorithm, &prefer_blob); + TEST_CHECK(ret == 0); + TEST_CHECK(algorithm == FLB_COMPRESSION_ALGORITHM_ZSTD); + TEST_CHECK(prefer_blob == FLB_FALSE); + + ctx.compress_blob = FLB_FALSE; + ctx.compression = FLB_COMPRESSION_ALGORITHM_NONE; + ret = azb_select_compression_strategy(&ctx, &algorithm, &prefer_blob); + TEST_CHECK(ret == 0); + TEST_CHECK(algorithm == FLB_COMPRESSION_ALGORITHM_NONE); + TEST_CHECK(prefer_blob == FLB_FALSE); + + azure_blob_ctx_destroy(&ctx); +} + +TEST_LIST = { + {"block_blob_extension_zstd", test_block_blob_extension_zstd}, + {"block_blob_extension_gzip_default", test_block_blob_extension_gzip_default}, + {"block_blob_extension_disabled", test_block_blob_extension_disabled}, + {"http_headers_zstd_encoding", test_http_headers_zstd_encoding}, + {"http_headers_zstd_content_type", test_http_headers_zstd_content_type}, + {"compression_strategy_precedence", test_compression_strategy_precedence}, + { 0 } +};