1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "google/cloud/storage/internal/curl_client.h"
16 #include "google/cloud/storage/iam_policy.h"
17 #include "google/cloud/storage/internal/curl_request_builder.h"
18 #include "google/cloud/storage/oauth2/credentials.h"
19 #include "google/cloud/storage/oauth2/google_credentials.h"
20 #include "google/cloud/internal/setenv.h"
21 #include "google/cloud/testing_util/scoped_environment.h"
22 #include <gmock/gmock.h>
23 #include <memory>
24 #include <utility>
25 #include <vector>
26
27 namespace google {
28 namespace cloud {
29 namespace storage {
30 inline namespace STORAGE_CLIENT_NS {
31 namespace internal {
32 namespace {
33
34 using ::google::cloud::storage::oauth2::Credentials;
35 using ::testing::HasSubstr;
36
37 StatusCode const kStatusErrorCode = StatusCode::kUnavailable;
38 std::string const kStatusErrorMsg = "FailingCredentials doing its job, failing";
39
40 // We create a credential class that always fails to fetch an access token; this
41 // allows us to check that CurlClient methods fail early when their setup steps
42 // (which include adding the authorization header) return a failure Status.
43 // Note that if the methods performing the setup steps were not templated, we
44 // could simply mock those out instead via MOCK_METHOD<N> macros.
45 class FailingCredentials : public Credentials {
46 public:
AuthorizationHeader()47 StatusOr<std::string> AuthorizationHeader() override {
48 return Status(kStatusErrorCode, kStatusErrorMsg);
49 }
50 };
51
52 class CurlClientTest : public ::testing::Test,
53 public ::testing::WithParamInterface<std::string> {
54 protected:
CurlClientTest()55 CurlClientTest() : endpoint_("CLOUD_STORAGE_TESTBENCH_ENDPOINT", {}) {}
56
SetUp()57 void SetUp() override {
58 std::string const error_type = GetParam();
59 if (error_type == "credentials-failure") {
60 client_ = CurlClient::Create(std::make_shared<FailingCredentials>());
61 // We know exactly what error to expect, so setup the assertions to be
62 // very strict.
63 check_status_ = [](Status const& actual) {
64 EXPECT_EQ(kStatusErrorCode, actual.code());
65 EXPECT_THAT(actual.message(), HasSubstr(kStatusErrorMsg));
66 };
67 } else if (error_type == "libcurl-failure") {
68 google::cloud::internal::SetEnv("CLOUD_STORAGE_TESTBENCH_ENDPOINT",
69 "http://localhost:1");
70 client_ =
71 CurlClient::Create(ClientOptions(oauth2::CreateAnonymousCredentials())
72 .set_endpoint("http://localhost:1"));
73 // We do not know what libcurl will return. Some kind of error, but varies
74 // by version of libcurl. Just make sure it is an error and the CURL
75 // details are included in the error message.
76 check_status_ = [](Status const& actual) {
77 EXPECT_FALSE(actual.ok());
78 EXPECT_THAT(actual.message(), HasSubstr("CURL error"));
79 };
80 } else {
81 FAIL() << "Invalid test parameter value: " << error_type
82 << ", expected either credentials-failure or libcurl-failure";
83 }
84 }
85
CheckStatus(Status const & actual)86 void CheckStatus(Status const& actual) { check_status_(actual); }
87
TearDown()88 void TearDown() override { client_.reset(); }
89
90 std::shared_ptr<CurlClient> client_;
91 std::function<void(Status const& status)> check_status_;
92 testing_util::ScopedEnvironment endpoint_;
93 };
94
TEST_P(CurlClientTest,UploadChunk)95 TEST_P(CurlClientTest, UploadChunk) {
96 // Use an invalid port (0) to force a libcurl failure
97 auto actual = client_
98 ->UploadChunk(UploadChunkRequest(
99 "http://localhost:1/invalid-session-id", 0,
100 {ConstBuffer{std::string{}}}, 0))
101 .status();
102 CheckStatus(actual);
103 }
104
TEST_P(CurlClientTest,QueryResumableUpload)105 TEST_P(CurlClientTest, QueryResumableUpload) {
106 // Use http://localhost:1 to force a libcurl failure
107 auto actual = client_
108 ->QueryResumableUpload(QueryResumableUploadRequest(
109 "http://localhost:9/invalid-session-id"))
110 .status();
111 CheckStatus(actual);
112 }
113
TEST_P(CurlClientTest,ListBuckets)114 TEST_P(CurlClientTest, ListBuckets) {
115 auto actual = client_->ListBuckets(ListBucketsRequest{"project_id"}).status();
116 CheckStatus(actual);
117 }
118
TEST_P(CurlClientTest,CreateBucket)119 TEST_P(CurlClientTest, CreateBucket) {
120 auto actual = client_
121 ->CreateBucket(CreateBucketRequest(
122 "bkt", BucketMetadata().set_name("bkt")))
123 .status();
124 CheckStatus(actual);
125 }
126
TEST_P(CurlClientTest,GetBucketMetadata)127 TEST_P(CurlClientTest, GetBucketMetadata) {
128 auto actual =
129 client_->GetBucketMetadata(GetBucketMetadataRequest("bkt")).status();
130 CheckStatus(actual);
131 }
132
TEST_P(CurlClientTest,DeleteBucket)133 TEST_P(CurlClientTest, DeleteBucket) {
134 auto actual = client_->DeleteBucket(DeleteBucketRequest("bkt")).status();
135 CheckStatus(actual);
136 }
137
TEST_P(CurlClientTest,UpdateBucket)138 TEST_P(CurlClientTest, UpdateBucket) {
139 auto actual =
140 client_
141 ->UpdateBucket(UpdateBucketRequest(BucketMetadata().set_name("bkt")))
142 .status();
143 CheckStatus(actual);
144 }
145
TEST_P(CurlClientTest,PatchBucket)146 TEST_P(CurlClientTest, PatchBucket) {
147 auto actual = client_
148 ->PatchBucket(PatchBucketRequest(
149 "bkt", BucketMetadata().set_name("bkt"),
150 BucketMetadata().set_name("bkt")))
151 .status();
152 CheckStatus(actual);
153 }
154
TEST_P(CurlClientTest,GetBucketIamPolicy)155 TEST_P(CurlClientTest, GetBucketIamPolicy) {
156 auto actual =
157 client_->GetBucketIamPolicy(GetBucketIamPolicyRequest("bkt")).status();
158 CheckStatus(actual);
159 }
160
TEST_P(CurlClientTest,GetNativeBucketIamPolicy)161 TEST_P(CurlClientTest, GetNativeBucketIamPolicy) {
162 auto actual =
163 client_->GetNativeBucketIamPolicy(GetBucketIamPolicyRequest("bkt"))
164 .status();
165 CheckStatus(actual);
166 }
167
TEST_P(CurlClientTest,SetBucketIamPolicy)168 TEST_P(CurlClientTest, SetBucketIamPolicy) {
169 auto actual = client_
170 ->SetBucketIamPolicy(SetBucketIamPolicyRequest(
171 "bkt", google::cloud::IamPolicy{}))
172 .status();
173 CheckStatus(actual);
174 }
175
TEST_P(CurlClientTest,SetNativeBucketIamPolicy)176 TEST_P(CurlClientTest, SetNativeBucketIamPolicy) {
177 auto actual =
178 client_
179 ->SetNativeBucketIamPolicy(SetNativeBucketIamPolicyRequest(
180 "bkt", NativeIamPolicy(std::vector<NativeIamBinding>())))
181 .status();
182 CheckStatus(actual);
183 }
184
TEST_P(CurlClientTest,TestBucketIamPermissions)185 TEST_P(CurlClientTest, TestBucketIamPermissions) {
186 auto actual =
187 client_
188 ->TestBucketIamPermissions(TestBucketIamPermissionsRequest("bkt", {}))
189 .status();
190 CheckStatus(actual);
191 }
192
TEST_P(CurlClientTest,LockBucketRetentionPolicy)193 TEST_P(CurlClientTest, LockBucketRetentionPolicy) {
194 auto actual = client_
195 ->LockBucketRetentionPolicy(
196 LockBucketRetentionPolicyRequest("bkt", 0))
197 .status();
198 CheckStatus(actual);
199 }
200
TEST_P(CurlClientTest,InsertObjectMediaSimple)201 TEST_P(CurlClientTest, InsertObjectMediaSimple) {
202 auto actual = client_
203 ->InsertObjectMedia(
204 InsertObjectMediaRequest("bkt", "obj", "contents")
205 .set_multiple_options(DisableMD5Hash(true),
206 DisableCrc32cChecksum(true)))
207 .status();
208 CheckStatus(actual);
209 }
210
TEST_P(CurlClientTest,InsertObjectMediaMultipart)211 TEST_P(CurlClientTest, InsertObjectMediaMultipart) {
212 auto actual = client_
213 ->InsertObjectMedia(
214 InsertObjectMediaRequest("bkt", "obj", "contents"))
215 .status();
216 CheckStatus(actual);
217 }
218
TEST_P(CurlClientTest,InsertObjectMediaXml)219 TEST_P(CurlClientTest, InsertObjectMediaXml) {
220 auto actual =
221 client_
222 ->InsertObjectMedia(InsertObjectMediaRequest("bkt", "obj", "contents")
223 .set_multiple_options(Fields("")))
224 .status();
225 CheckStatus(actual);
226 }
227
TEST_P(CurlClientTest,GetObjectMetadata)228 TEST_P(CurlClientTest, GetObjectMetadata) {
229 auto actual =
230 client_->GetObjectMetadata(GetObjectMetadataRequest("bkt", "obj"))
231 .status();
232 CheckStatus(actual);
233 }
234
TEST_P(CurlClientTest,ReadObjectXml)235 TEST_P(CurlClientTest, ReadObjectXml) {
236 if (GetParam() == "libcurl-failure") {
237 return;
238 }
239 auto actual =
240 client_->ReadObject(ReadObjectRangeRequest("bkt", "obj")).status();
241 CheckStatus(actual);
242 }
243
TEST_P(CurlClientTest,ReadObjectJson)244 TEST_P(CurlClientTest, ReadObjectJson) {
245 if (GetParam() == "libcurl-failure") {
246 return;
247 }
248 auto actual =
249 client_
250 ->ReadObject(ReadObjectRangeRequest("bkt", "obj")
251 .set_multiple_options(IfGenerationNotMatch(0)))
252 .status();
253 CheckStatus(actual);
254 }
255
TEST_P(CurlClientTest,ListObjects)256 TEST_P(CurlClientTest, ListObjects) {
257 auto actual = client_->ListObjects(ListObjectsRequest("bkt")).status();
258 CheckStatus(actual);
259 }
260
TEST_P(CurlClientTest,DeleteObject)261 TEST_P(CurlClientTest, DeleteObject) {
262 auto actual =
263 client_->DeleteObject(DeleteObjectRequest("bkt", "obj")).status();
264 CheckStatus(actual);
265 }
266
TEST_P(CurlClientTest,UpdateObject)267 TEST_P(CurlClientTest, UpdateObject) {
268 auto actual =
269 client_->UpdateObject(UpdateObjectRequest("bkt", "obj", ObjectMetadata()))
270 .status();
271 CheckStatus(actual);
272 }
273
TEST_P(CurlClientTest,PatchObject)274 TEST_P(CurlClientTest, PatchObject) {
275 auto actual = client_
276 ->PatchObject(PatchObjectRequest(
277 "bkt", "obj", ObjectMetadata(), ObjectMetadata()))
278 .status();
279 CheckStatus(actual);
280 }
281
TEST_P(CurlClientTest,ComposeObject)282 TEST_P(CurlClientTest, ComposeObject) {
283 auto actual =
284 client_->ComposeObject(ComposeObjectRequest("bkt", {}, "obj")).status();
285 CheckStatus(actual);
286 }
287
TEST_P(CurlClientTest,ListBucketAcl)288 TEST_P(CurlClientTest, ListBucketAcl) {
289 auto actual = client_->ListBucketAcl(ListBucketAclRequest("bkt")).status();
290 CheckStatus(actual);
291 }
292
TEST_P(CurlClientTest,CopyObject)293 TEST_P(CurlClientTest, CopyObject) {
294 auto actual =
295 client_->CopyObject(CopyObjectRequest("bkt", "obj1", "bkt", "obj2"))
296 .status();
297 CheckStatus(actual);
298 }
299
TEST_P(CurlClientTest,CreateBucketAcl)300 TEST_P(CurlClientTest, CreateBucketAcl) {
301 auto actual =
302 client_->CreateBucketAcl(CreateBucketAclRequest("bkt", "entity", "role"))
303 .status();
304 CheckStatus(actual);
305 }
306
TEST_P(CurlClientTest,GetBucketAcl)307 TEST_P(CurlClientTest, GetBucketAcl) {
308 auto actual =
309 client_->GetBucketAcl(GetBucketAclRequest("bkt", "entity")).status();
310 CheckStatus(actual);
311 }
312
TEST_P(CurlClientTest,DeleteBucketAcl)313 TEST_P(CurlClientTest, DeleteBucketAcl) {
314 auto actual =
315 client_->DeleteBucketAcl(DeleteBucketAclRequest("bkt", "entity"))
316 .status();
317 CheckStatus(actual);
318 }
319
TEST_P(CurlClientTest,UpdateBucketAcl)320 TEST_P(CurlClientTest, UpdateBucketAcl) {
321 auto actual =
322 client_->UpdateBucketAcl(UpdateBucketAclRequest("bkt", "entity", "role"))
323 .status();
324 CheckStatus(actual);
325 }
326
TEST_P(CurlClientTest,PatchBucketAcl)327 TEST_P(CurlClientTest, PatchBucketAcl) {
328 auto actual =
329 client_
330 ->PatchBucketAcl(PatchBucketAclRequest(
331 "bkt", "entity", BucketAccessControl(), BucketAccessControl()))
332 .status();
333 CheckStatus(actual);
334 }
335
TEST_P(CurlClientTest,ListObjectAcl)336 TEST_P(CurlClientTest, ListObjectAcl) {
337 auto actual =
338 client_->ListObjectAcl(ListObjectAclRequest("bkt", "obj")).status();
339 CheckStatus(actual);
340 }
341
TEST_P(CurlClientTest,CreateObjectAcl)342 TEST_P(CurlClientTest, CreateObjectAcl) {
343 auto actual = client_
344 ->CreateObjectAcl(
345 CreateObjectAclRequest("bkt", "obj", "entity", "role"))
346 .status();
347 CheckStatus(actual);
348 }
349
TEST_P(CurlClientTest,DeleteObjectAcl)350 TEST_P(CurlClientTest, DeleteObjectAcl) {
351 auto actual =
352 client_->DeleteObjectAcl(DeleteObjectAclRequest("bkt", "obj", "entity"))
353 .status();
354 CheckStatus(actual);
355 }
356
TEST_P(CurlClientTest,GetObjectAcl)357 TEST_P(CurlClientTest, GetObjectAcl) {
358 auto actual =
359 client_->GetObjectAcl(GetObjectAclRequest("bkt", "obj", "entity"))
360 .status();
361 CheckStatus(actual);
362 }
363
TEST_P(CurlClientTest,UpdateObjectAcl)364 TEST_P(CurlClientTest, UpdateObjectAcl) {
365 auto actual = client_
366 ->UpdateObjectAcl(
367 UpdateObjectAclRequest("bkt", "obj", "entity", "role"))
368 .status();
369 CheckStatus(actual);
370 }
371
TEST_P(CurlClientTest,PatchObjectAcl)372 TEST_P(CurlClientTest, PatchObjectAcl) {
373 auto actual = client_
374 ->PatchObjectAcl(PatchObjectAclRequest(
375 "bkt", "obj", "entity", ObjectAccessControl(),
376 ObjectAccessControl()))
377 .status();
378 CheckStatus(actual);
379 }
380
TEST_P(CurlClientTest,RewriteObject)381 TEST_P(CurlClientTest, RewriteObject) {
382 auto actual = client_
383 ->RewriteObject(RewriteObjectRequest("bkt", "obj", "bkt2",
384 "obj2", "token"))
385 .status();
386 CheckStatus(actual);
387 }
388
TEST_P(CurlClientTest,CreateResumableSession)389 TEST_P(CurlClientTest, CreateResumableSession) {
390 auto actual = client_
391 ->CreateResumableSession(
392 ResumableUploadRequest("test-bucket", "test-object"))
393 .status();
394 CheckStatus(actual);
395 }
396
TEST_P(CurlClientTest,DeleteResumableUpload)397 TEST_P(CurlClientTest, DeleteResumableUpload) {
398 auto actual = client_
399 ->DeleteResumableUpload(
400 DeleteResumableUploadRequest("test-upload-session-url"))
401 .status();
402 CheckStatus(actual);
403 }
404
TEST_P(CurlClientTest,ListDefaultObjectAcl)405 TEST_P(CurlClientTest, ListDefaultObjectAcl) {
406 auto actual =
407 client_->ListDefaultObjectAcl(ListDefaultObjectAclRequest("bkt"))
408 .status();
409 CheckStatus(actual);
410 }
411
TEST_P(CurlClientTest,CreateDefaultObjectAcl)412 TEST_P(CurlClientTest, CreateDefaultObjectAcl) {
413 auto actual = client_
414 ->CreateDefaultObjectAcl(
415 CreateDefaultObjectAclRequest("bkt", "entity", "role"))
416 .status();
417 CheckStatus(actual);
418 }
419
TEST_P(CurlClientTest,DeleteDefaultObjectAcl)420 TEST_P(CurlClientTest, DeleteDefaultObjectAcl) {
421 auto actual = client_
422 ->DeleteDefaultObjectAcl(
423 DeleteDefaultObjectAclRequest("bkt", "entity"))
424 .status();
425 CheckStatus(actual);
426 }
427
TEST_P(CurlClientTest,GetDefaultObjectAcl)428 TEST_P(CurlClientTest, GetDefaultObjectAcl) {
429 auto actual =
430 client_->GetDefaultObjectAcl(GetDefaultObjectAclRequest("bkt", "entity"))
431 .status();
432 CheckStatus(actual);
433 }
434
TEST_P(CurlClientTest,UpdateDefaultObjectAcl)435 TEST_P(CurlClientTest, UpdateDefaultObjectAcl) {
436 auto actual = client_
437 ->UpdateDefaultObjectAcl(
438 UpdateDefaultObjectAclRequest("bkt", "entity", "role"))
439 .status();
440 CheckStatus(actual);
441 }
442
TEST_P(CurlClientTest,PatchDefaultObjectAcl)443 TEST_P(CurlClientTest, PatchDefaultObjectAcl) {
444 auto actual =
445 client_
446 ->PatchDefaultObjectAcl(PatchDefaultObjectAclRequest(
447 "bkt", "entity", ObjectAccessControl(), ObjectAccessControl()))
448 .status();
449 CheckStatus(actual);
450 }
451
TEST_P(CurlClientTest,GetServiceAccount)452 TEST_P(CurlClientTest, GetServiceAccount) {
453 auto actual =
454 client_->GetServiceAccount(GetProjectServiceAccountRequest("project_id"))
455 .status();
456 CheckStatus(actual);
457 }
458
TEST_P(CurlClientTest,ListHmacKeyRequest)459 TEST_P(CurlClientTest, ListHmacKeyRequest) {
460 auto status =
461 client_->ListHmacKeys(ListHmacKeysRequest("project_id")).status();
462 CheckStatus(status);
463 }
464
TEST_P(CurlClientTest,CreateHmacKeyRequest)465 TEST_P(CurlClientTest, CreateHmacKeyRequest) {
466 auto actual =
467 client_
468 ->CreateHmacKey(CreateHmacKeyRequest("project_id", "service-account"))
469 .status();
470 CheckStatus(actual);
471 }
472
TEST_P(CurlClientTest,SignBlob)473 TEST_P(CurlClientTest, SignBlob) {
474 auto actual =
475 client_
476 ->SignBlob(SignBlobRequest("test-service-account", "test-blob", {}))
477 .status();
478 CheckStatus(actual);
479 }
480
TEST_P(CurlClientTest,ListNotifications)481 TEST_P(CurlClientTest, ListNotifications) {
482 auto actual =
483 client_->ListNotifications(ListNotificationsRequest("bkt")).status();
484 CheckStatus(actual);
485 }
486
TEST_P(CurlClientTest,CreateNotification)487 TEST_P(CurlClientTest, CreateNotification) {
488 auto actual = client_
489 ->CreateNotification(CreateNotificationRequest(
490 "bkt", NotificationMetadata()))
491 .status();
492 CheckStatus(actual);
493 }
494
TEST_P(CurlClientTest,GetNotification)495 TEST_P(CurlClientTest, GetNotification) {
496 auto actual =
497 client_->GetNotification(GetNotificationRequest("bkt", "notification_id"))
498 .status();
499 CheckStatus(actual);
500 }
501
TEST_P(CurlClientTest,DeleteNotification)502 TEST_P(CurlClientTest, DeleteNotification) {
503 auto actual = client_
504 ->DeleteNotification(
505 DeleteNotificationRequest("bkt", "notification_id"))
506 .status();
507 CheckStatus(actual);
508 }
509
510 INSTANTIATE_TEST_SUITE_P(CredentialsFailure, CurlClientTest,
511 ::testing::Values("credentials-failure"));
512
513 INSTANTIATE_TEST_SUITE_P(LibCurlFailure, CurlClientTest,
514 ::testing::Values("libcurl-failure"));
515
516 } // namespace
517 } // namespace internal
518 } // namespace STORAGE_CLIENT_NS
519 } // namespace storage
520 } // namespace cloud
521 } // namespace google
522