1 /**
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  * SPDX-License-Identifier: Apache-2.0.
4  */
5 
6 #include "aws/s3/private/s3_client_impl.h"
7 #include "s3_tester.h"
8 #include <aws/io/channel_bootstrap.h>
9 #include <aws/testing/aws_test_harness.h>
10 
s_test_s3_endpoint_ref_zero_ref_callback(struct aws_s3_endpoint * endpoint)11 static bool s_test_s3_endpoint_ref_zero_ref_callback(struct aws_s3_endpoint *endpoint) {
12     struct aws_s3_tester *tester = endpoint->user_data;
13 
14     if (aws_s3_tester_inc_counter1(tester) == 1) {
15         return false;
16     }
17 
18     return true;
19 }
20 
s_test_s3_endpoint_ref_shutdown(void * user_data)21 static void s_test_s3_endpoint_ref_shutdown(void *user_data) {
22     struct aws_s3_tester *tester = user_data;
23 
24     aws_s3_tester_inc_counter1(tester);
25 }
26 
AWS_TEST_CASE(test_s3_endpoint_ref,s_test_s3_endpoint_ref)27 AWS_TEST_CASE(test_s3_endpoint_ref, s_test_s3_endpoint_ref)
28 static int s_test_s3_endpoint_ref(struct aws_allocator *allocator, void *ctx) {
29     (void)ctx;
30 
31     struct aws_s3_tester tester;
32     ASSERT_SUCCESS(aws_s3_tester_init(allocator, &tester));
33     aws_s3_tester_set_counter1_desired(&tester, 3);
34 
35     struct aws_string *host_name =
36         aws_s3_tester_build_endpoint_string(allocator, &g_test_public_bucket_name, &g_test_s3_region);
37 
38     struct aws_s3_endpoint_options endpoint_options = {
39         .host_name = host_name,
40         .ref_count_zero_callback = s_test_s3_endpoint_ref_zero_ref_callback,
41         .shutdown_callback = s_test_s3_endpoint_ref_shutdown,
42         .client_bootstrap = tester.client_bootstrap,
43         .tls_connection_options = NULL,
44         .dns_host_address_ttl_seconds = 1,
45         .user_data = &tester,
46         .max_connections = 4,
47     };
48 
49     struct aws_s3_endpoint *endpoint = aws_s3_endpoint_new(allocator, &endpoint_options);
50 
51     ASSERT_TRUE(endpoint->http_connection_manager != NULL);
52 
53     /* During the first release, s_test_s3_endpoint_ref_zero_ref_callback will return false, which will mean it does not
54      * get cleaned up. */
55     aws_s3_endpoint_release(endpoint);
56     ASSERT_TRUE(aws_atomic_load_int(&endpoint->ref_count.ref_count) == 0);
57 
58     /* Perform an acquire, bumping the ref count to 1. */
59     aws_s3_endpoint_acquire(endpoint);
60     ASSERT_TRUE(aws_atomic_load_int(&endpoint->ref_count.ref_count) == 1);
61 
62     /* During the secnod release, s_test_s3_endpoint_ref_zero_ref_callback will return true, causing clean up to
63      * occur.*/
64     aws_s3_endpoint_release(endpoint);
65 
66     /* Wait for shutdown callback to increment the counter, hitting 3. */
67     aws_s3_tester_wait_for_counters(&tester);
68 
69     aws_string_destroy(host_name);
70     aws_s3_tester_clean_up(&tester);
71 
72     return 0;
73 }
74 
s_test_s3_endpoint_resurrect_endpoint_ref_count_zero(struct aws_s3_endpoint * endpoint)75 static bool s_test_s3_endpoint_resurrect_endpoint_ref_count_zero(struct aws_s3_endpoint *endpoint) {
76     struct aws_s3_client *client = endpoint->user_data;
77     struct aws_s3_tester *tester = client->shutdown_callback_user_data;
78 
79     bool acquire_and_release_endpoint = false;
80 
81     if (aws_s3_tester_inc_counter1(tester) == 1) {
82         acquire_and_release_endpoint = true;
83         aws_s3_endpoint_acquire(endpoint);
84     }
85 
86     struct aws_s3_client_vtable *original_client_vtable =
87         aws_s3_tester_get_client_vtable_patch(tester, 0)->original_vtable;
88 
89     bool result = original_client_vtable->endpoint_ref_count_zero(endpoint);
90 
91     if (acquire_and_release_endpoint) {
92         aws_s3_endpoint_release(endpoint);
93     }
94 
95     return result;
96 }
97 
AWS_TEST_CASE(test_s3_endpoint_resurrect,s_test_s3_endpoint_resurrect)98 AWS_TEST_CASE(test_s3_endpoint_resurrect, s_test_s3_endpoint_resurrect)
99 static int s_test_s3_endpoint_resurrect(struct aws_allocator *allocator, void *ctx) {
100     (void)ctx;
101 
102     struct aws_s3_tester tester;
103     ASSERT_SUCCESS(aws_s3_tester_init(allocator, &tester));
104 
105     struct aws_s3_tester_client_options client_options;
106     AWS_ZERO_STRUCT(client_options);
107 
108     struct aws_s3_client *client = NULL;
109     ASSERT_SUCCESS(aws_s3_tester_client_new(&tester, &client_options, &client));
110 
111     struct aws_s3_client_vtable *patched_client_vtable = aws_s3_tester_patch_client_vtable(&tester, client, NULL);
112     patched_client_vtable->endpoint_ref_count_zero = s_test_s3_endpoint_resurrect_endpoint_ref_count_zero;
113 
114     struct aws_s3_tester_meta_request_options options = {
115         .allocator = allocator,
116         .client = client,
117         .meta_request_type = AWS_S3_META_REQUEST_TYPE_GET_OBJECT,
118         .validate_type = AWS_S3_TESTER_VALIDATE_TYPE_EXPECT_SUCCESS,
119         .get_options =
120             {
121                 .object_path = g_pre_existing_object_1MB,
122             },
123     };
124 
125     ASSERT_SUCCESS(aws_s3_tester_send_meta_request_with_options(&tester, &options, NULL));
126 
127     aws_s3_client_release(client);
128     aws_s3_tester_clean_up(&tester);
129 
130     return 0;
131 }
132 
AWS_TEST_CASE(test_s3_different_endpoints,s_test_s3_different_endpoints)133 AWS_TEST_CASE(test_s3_different_endpoints, s_test_s3_different_endpoints)
134 static int s_test_s3_different_endpoints(struct aws_allocator *allocator, void *ctx) {
135     (void)ctx;
136 
137     struct aws_s3_tester tester;
138     ASSERT_SUCCESS(aws_s3_tester_init(allocator, &tester));
139 
140     struct aws_s3_client *client = NULL;
141     struct aws_s3_tester_client_options client_options;
142     AWS_ZERO_STRUCT(client_options);
143 
144     ASSERT_SUCCESS(aws_s3_tester_client_new(&tester, &client_options, &client));
145 
146     {
147         struct aws_s3_meta_request_test_results meta_request_test_results;
148         AWS_ZERO_STRUCT(meta_request_test_results);
149 
150         struct aws_s3_tester_meta_request_options options = {
151             .allocator = allocator,
152             .client = client,
153             .meta_request_type = AWS_S3_META_REQUEST_TYPE_GET_OBJECT,
154             .validate_type = AWS_S3_TESTER_VALIDATE_TYPE_EXPECT_SUCCESS,
155             .get_options =
156                 {
157                     .object_path = g_s3_path_get_object_test_1MB,
158                 },
159         };
160 
161         ASSERT_SUCCESS(aws_s3_tester_send_meta_request_with_options(&tester, &options, &meta_request_test_results));
162         aws_s3_meta_request_test_results_clean_up(&meta_request_test_results);
163     }
164 
165     {
166         struct aws_s3_meta_request_test_results meta_request_test_results;
167         AWS_ZERO_STRUCT(meta_request_test_results);
168 
169         struct aws_s3_tester_meta_request_options options = {
170             .allocator = allocator,
171             .client = client,
172             .meta_request_type = AWS_S3_META_REQUEST_TYPE_GET_OBJECT,
173             .validate_type = AWS_S3_TESTER_VALIDATE_TYPE_EXPECT_SUCCESS,
174             .bucket_name = &g_test_public_bucket_name,
175             .get_options =
176                 {
177                     .object_path = g_s3_path_get_object_test_1MB,
178                 },
179         };
180 
181         ASSERT_SUCCESS(aws_s3_tester_send_meta_request_with_options(&tester, &options, &meta_request_test_results));
182         aws_s3_meta_request_test_results_clean_up(&meta_request_test_results);
183     }
184 
185     aws_s3_client_release(client);
186 
187     aws_s3_tester_clean_up(&tester);
188 
189     return 0;
190 }
191