|
| 1 | +/** |
| 2 | + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| 3 | + * SPDX-License-Identifier: Apache-2.0. |
| 4 | + */ |
| 5 | + |
| 6 | +#include "s3_tester.h" |
| 7 | +#include <aws/common/environment.h> |
| 8 | +#include <aws/s3/private/s3_default_buffer_pool.h> |
| 9 | +#include <aws/s3/private/s3_util.h> |
| 10 | +#include <aws/testing/aws_test_harness.h> |
| 11 | + |
| 12 | +#define TEST_CASE(NAME) \ |
| 13 | + AWS_TEST_CASE(NAME, s_test_##NAME); \ |
| 14 | + static int s_test_##NAME(struct aws_allocator *allocator, void *ctx) |
| 15 | + |
| 16 | +static const char *s_memory_limit_env_var = "AWS_CRT_S3_MEMORY_LIMIT_IN_GIB"; |
| 17 | + |
| 18 | +/* Copied from s3_default_buffer_pool.c */ |
| 19 | +static const size_t s_buffer_pool_reserved_mem = MB_TO_BYTES(128); |
| 20 | + |
| 21 | +/** |
| 22 | + * Test that memory limit can be set via environment variable when config value is 0 |
| 23 | + */ |
| 24 | +TEST_CASE(s3_client_memory_limit_from_env_var_valid) { |
| 25 | + (void)ctx; |
| 26 | + struct aws_s3_tester tester; |
| 27 | + ASSERT_SUCCESS(aws_s3_tester_init(allocator, &tester)); |
| 28 | + |
| 29 | + /* Set environment variable to 4 GiB */ |
| 30 | + struct aws_string *env_var_name = aws_string_new_from_c_str(allocator, s_memory_limit_env_var); |
| 31 | + struct aws_string *env_var_value = aws_string_new_from_c_str(allocator, "1"); |
| 32 | + ASSERT_SUCCESS(aws_set_environment_value(env_var_name, env_var_value)); |
| 33 | + |
| 34 | + struct aws_s3_client_config client_config = { |
| 35 | + .part_size = MB_TO_BYTES(8), |
| 36 | + .throughput_target_gbps = 10.0, |
| 37 | + .memory_limit_in_bytes = 0, /* Will read from environment variable */ |
| 38 | + }; |
| 39 | + |
| 40 | + ASSERT_SUCCESS(aws_s3_tester_bind_client( |
| 41 | + &tester, &client_config, AWS_S3_TESTER_BIND_CLIENT_REGION | AWS_S3_TESTER_BIND_CLIENT_SIGNING)); |
| 42 | + |
| 43 | + struct aws_s3_client *client = aws_s3_client_new(allocator, &client_config); |
| 44 | + ASSERT_TRUE(client != NULL); |
| 45 | + |
| 46 | + /* Verify that buffer pool was configured with 4 GiB limit */ |
| 47 | + size_t expected_memory_limit = GB_TO_BYTES(1) - s_buffer_pool_reserved_mem; |
| 48 | + ASSERT_TRUE(client->buffer_pool != NULL); |
| 49 | + struct aws_s3_default_buffer_pool_usage_stats stats = aws_s3_default_buffer_pool_get_usage(client->buffer_pool); |
| 50 | + ASSERT_UINT_EQUALS(stats.mem_limit, expected_memory_limit); |
| 51 | + |
| 52 | + aws_s3_client_release(client); |
| 53 | + |
| 54 | + /* Clean up environment variable */ |
| 55 | + aws_string_destroy(env_var_name); |
| 56 | + aws_string_destroy(env_var_value); |
| 57 | + |
| 58 | + aws_s3_tester_clean_up(&tester); |
| 59 | + return AWS_OP_SUCCESS; |
| 60 | +} |
| 61 | + |
| 62 | +/** |
| 63 | + * Test that config value takes precedence over environment variable |
| 64 | + */ |
| 65 | +TEST_CASE(s3_client_memory_limit_config_takes_precedence) { |
| 66 | + (void)ctx; |
| 67 | + struct aws_s3_tester tester; |
| 68 | + ASSERT_SUCCESS(aws_s3_tester_init(allocator, &tester)); |
| 69 | + |
| 70 | + /* Set environment variable to 4 GiB */ |
| 71 | + struct aws_string *env_var_name = aws_string_new_from_c_str(allocator, s_memory_limit_env_var); |
| 72 | + struct aws_string *env_var_value = aws_string_new_from_c_str(allocator, "1"); |
| 73 | + ASSERT_SUCCESS(aws_set_environment_value(env_var_name, env_var_value)); |
| 74 | + aws_string_destroy(env_var_name); |
| 75 | + aws_string_destroy(env_var_value); |
| 76 | + |
| 77 | + struct aws_s3_client_config client_config = { |
| 78 | + .part_size = MB_TO_BYTES(8), |
| 79 | + .throughput_target_gbps = 10.0, |
| 80 | + .memory_limit_in_bytes = GB_TO_BYTES(2), /* Config value should take precedence */ |
| 81 | + }; |
| 82 | + ASSERT_SUCCESS(aws_s3_tester_bind_client( |
| 83 | + &tester, &client_config, AWS_S3_TESTER_BIND_CLIENT_REGION | AWS_S3_TESTER_BIND_CLIENT_SIGNING)); |
| 84 | + |
| 85 | + struct aws_s3_client *client = aws_s3_client_new(allocator, &client_config); |
| 86 | + ASSERT_TRUE(client != NULL); |
| 87 | + |
| 88 | + /* The 2 GiB from config should be used, not the 1 GiB from env var */ |
| 89 | + ASSERT_TRUE(client->buffer_pool != NULL); |
| 90 | + size_t expected_memory_limit = GB_TO_BYTES(2) - s_buffer_pool_reserved_mem; |
| 91 | + ASSERT_TRUE(client->buffer_pool != NULL); |
| 92 | + struct aws_s3_default_buffer_pool_usage_stats stats = aws_s3_default_buffer_pool_get_usage(client->buffer_pool); |
| 93 | + ASSERT_UINT_EQUALS(stats.mem_limit, expected_memory_limit); |
| 94 | + |
| 95 | + aws_s3_client_release(client); |
| 96 | + |
| 97 | + /* Clean up environment variable */ |
| 98 | + env_var_name = aws_string_new_from_c_str(allocator, s_memory_limit_env_var); |
| 99 | + ASSERT_SUCCESS(aws_unset_environment_value(env_var_name)); |
| 100 | + aws_string_destroy(env_var_name); |
| 101 | + |
| 102 | + aws_s3_tester_clean_up(&tester); |
| 103 | + return AWS_OP_SUCCESS; |
| 104 | +} |
| 105 | + |
| 106 | +/** |
| 107 | + * Test that invalid environment variable value causes client creation to fail |
| 108 | + */ |
| 109 | +TEST_CASE(s3_client_memory_limit_from_env_var_invalid) { |
| 110 | + (void)ctx; |
| 111 | + struct aws_s3_tester tester; |
| 112 | + ASSERT_SUCCESS(aws_s3_tester_init(allocator, &tester)); |
| 113 | + |
| 114 | + /* Set environment variable to invalid value */ |
| 115 | + struct aws_string *env_var_name = aws_string_new_from_c_str(allocator, s_memory_limit_env_var); |
| 116 | + struct aws_string *env_var_value = aws_string_new_from_c_str(allocator, "invalid"); |
| 117 | + ASSERT_SUCCESS(aws_set_environment_value(env_var_name, env_var_value)); |
| 118 | + aws_string_destroy(env_var_name); |
| 119 | + aws_string_destroy(env_var_value); |
| 120 | + |
| 121 | + struct aws_s3_client_config client_config = { |
| 122 | + .part_size = MB_TO_BYTES(8), |
| 123 | + .throughput_target_gbps = 10.0, |
| 124 | + .memory_limit_in_bytes = 0, /* Will try to read from environment variable */ |
| 125 | + }; |
| 126 | + ASSERT_SUCCESS(aws_s3_tester_bind_client( |
| 127 | + &tester, &client_config, AWS_S3_TESTER_BIND_CLIENT_REGION | AWS_S3_TESTER_BIND_CLIENT_SIGNING)); |
| 128 | + |
| 129 | + /* Client creation should fail due to invalid env var value */ |
| 130 | + struct aws_s3_client *client = aws_s3_client_new(allocator, &client_config); |
| 131 | + ASSERT_TRUE(client == NULL); |
| 132 | + ASSERT_INT_EQUALS(AWS_ERROR_INVALID_ARGUMENT, aws_last_error()); |
| 133 | + /* Client failed to set up. */ |
| 134 | + tester.bound_to_client = false; |
| 135 | + /* Clean up environment variable */ |
| 136 | + env_var_name = aws_string_new_from_c_str(allocator, s_memory_limit_env_var); |
| 137 | + ASSERT_SUCCESS(aws_unset_environment_value(env_var_name)); |
| 138 | + aws_string_destroy(env_var_name); |
| 139 | + |
| 140 | + aws_s3_tester_clean_up(&tester); |
| 141 | + return AWS_OP_SUCCESS; |
| 142 | +} |
| 143 | + |
| 144 | +/** |
| 145 | + * Test that environment variable with value causing overflow is handled properly |
| 146 | + */ |
| 147 | +TEST_CASE(s3_client_memory_limit_from_env_var_overflow) { |
| 148 | + (void)ctx; |
| 149 | + struct aws_s3_tester tester; |
| 150 | + ASSERT_SUCCESS(aws_s3_tester_init(allocator, &tester)); |
| 151 | + |
| 152 | + /* Set environment variable to a very large value that would overflow when converted to bytes */ |
| 153 | + struct aws_string *env_var_name = aws_string_new_from_c_str(allocator, s_memory_limit_env_var); |
| 154 | + struct aws_string *env_var_value = aws_string_new_from_c_str(allocator, "18446744073709551615"); /* UINT64_MAX */ |
| 155 | + ASSERT_SUCCESS(aws_set_environment_value(env_var_name, env_var_value)); |
| 156 | + aws_string_destroy(env_var_name); |
| 157 | + aws_string_destroy(env_var_value); |
| 158 | + |
| 159 | + struct aws_s3_client_config client_config = { |
| 160 | + .part_size = MB_TO_BYTES(8), |
| 161 | + .throughput_target_gbps = 10.0, |
| 162 | + .memory_limit_in_bytes = 0, /* Will try to read from environment variable */ |
| 163 | + }; |
| 164 | + |
| 165 | + ASSERT_SUCCESS(aws_s3_tester_bind_client( |
| 166 | + &tester, &client_config, AWS_S3_TESTER_BIND_CLIENT_REGION | AWS_S3_TESTER_BIND_CLIENT_SIGNING)); |
| 167 | + |
| 168 | + /* Client creation should fail due to overflow during GiB to bytes conversion */ |
| 169 | + struct aws_s3_client *client = aws_s3_client_new(allocator, &client_config); |
| 170 | + ASSERT_TRUE(client == NULL); |
| 171 | + ASSERT_INT_EQUALS(AWS_ERROR_INVALID_ARGUMENT, aws_last_error()); |
| 172 | + /* Client failed to set up. */ |
| 173 | + tester.bound_to_client = false; |
| 174 | + |
| 175 | + /* Clean up environment variable */ |
| 176 | + env_var_name = aws_string_new_from_c_str(allocator, s_memory_limit_env_var); |
| 177 | + ASSERT_SUCCESS(aws_unset_environment_value(env_var_name)); |
| 178 | + aws_string_destroy(env_var_name); |
| 179 | + aws_s3_tester_clean_up(&tester); |
| 180 | + return AWS_OP_SUCCESS; |
| 181 | +} |
0 commit comments