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/client.h"
16 #include "google/cloud/storage/list_objects_reader.h"
17 #include "google/cloud/storage/testing/remove_stale_buckets.h"
18 #include "google/cloud/storage/testing/storage_integration_test.h"
19 #include "google/cloud/internal/getenv.h"
20 #include "google/cloud/testing_util/assert_ok.h"
21 #include "google/cloud/testing_util/contains_once.h"
22 #include <gmock/gmock.h>
23 #include <chrono>
24 #include <thread>
25
26 namespace google {
27 namespace cloud {
28 namespace storage {
29 inline namespace STORAGE_CLIENT_NS {
30 namespace {
31
32 using ::google::cloud::storage::testing::AclEntityNames;
33 using ::google::cloud::testing_util::ContainsOnce;
34 using ::testing::Contains;
35 using ::testing::ElementsAreArray;
36 using ::testing::HasSubstr;
37 using ::testing::Not;
38
39 class BucketIntegrationTest
40 : public google::cloud::storage::testing::StorageIntegrationTest {
41 protected:
SetUp()42 void SetUp() override {
43 project_id_ =
44 google::cloud::internal::GetEnv("GOOGLE_CLOUD_PROJECT").value_or("");
45 ASSERT_FALSE(project_id_.empty());
46 bucket_name_ = google::cloud::internal::GetEnv(
47 "GOOGLE_CLOUD_CPP_STORAGE_TEST_BUCKET_NAME")
48 .value_or("");
49 ASSERT_FALSE(bucket_name_.empty());
50 topic_name_ = google::cloud::internal::GetEnv(
51 "GOOGLE_CLOUD_CPP_STORAGE_TEST_TOPIC_NAME")
52 .value_or("");
53 ASSERT_FALSE(topic_name_.empty());
54 service_account_ = google::cloud::internal::GetEnv(
55 "GOOGLE_CLOUD_CPP_STORAGE_TEST_SERVICE_ACCOUNT")
56 .value_or("");
57 ASSERT_FALSE(service_account_.empty());
58 }
59
MakeEntityName()60 std::string MakeEntityName() {
61 // We always use the viewers for the project because it is known to exist.
62 return "project-viewers-" + project_id_;
63 }
64
65 std::string project_id_;
66 std::string bucket_name_;
67 std::string topic_name_;
68 std::string service_account_;
69 };
70
TEST_F(BucketIntegrationTest,BasicCRUD)71 TEST_F(BucketIntegrationTest, BasicCRUD) {
72 std::string bucket_name = MakeRandomBucketName();
73 StatusOr<Client> client = MakeBucketIntegrationTestClient();
74 ASSERT_STATUS_OK(client);
75
76 // We use this test to remove any buckets created by the integration tests
77 // more than 48 hours ago.
78 testing::RemoveStaleBuckets(
79 *client, RandomBucketNamePrefix(),
80 std::chrono::system_clock::now() - std::chrono::hours(48));
81
82 auto list_bucket_names = [&client, this] {
83 std::vector<std::string> names;
84 for (auto b : client->ListBucketsForProject(project_id_)) {
85 EXPECT_STATUS_OK(b);
86 if (!b) break;
87 names.push_back(b->name());
88 }
89 return names;
90 };
91 ASSERT_THAT(list_bucket_names(), Not(Contains(bucket_name)))
92 << "Test aborted. The bucket <" << bucket_name << "> already exists."
93 << " This is unexpected as the test generates a random bucket name.";
94
95 auto insert_meta = client->CreateBucketForProject(bucket_name, project_id_,
96 BucketMetadata());
97 ASSERT_STATUS_OK(insert_meta);
98 EXPECT_EQ(bucket_name, insert_meta->name());
99 EXPECT_THAT(list_bucket_names(), ContainsOnce(bucket_name));
100
101 StatusOr<BucketMetadata> get_meta = client->GetBucketMetadata(bucket_name);
102 ASSERT_STATUS_OK(get_meta);
103 EXPECT_EQ(*insert_meta, *get_meta);
104
105 // Create a request to update the metadata, change the storage class because
106 // it is easy. And use either COLDLINE or NEARLINE depending on the existing
107 // value.
108 std::string desired_storage_class = storage_class::Coldline();
109 if (get_meta->storage_class() == storage_class::Coldline()) {
110 desired_storage_class = storage_class::Nearline();
111 }
112 BucketMetadata update = *get_meta;
113 update.set_storage_class(desired_storage_class);
114 StatusOr<BucketMetadata> updated_meta =
115 client->UpdateBucket(bucket_name, update);
116 ASSERT_STATUS_OK(updated_meta);
117 EXPECT_EQ(desired_storage_class, updated_meta->storage_class());
118
119 // Patch the metadata to change the storage class, add some lifecycle
120 // rules, and the website settings.
121 BucketMetadata desired_state = *updated_meta;
122 LifecycleRule rule(LifecycleRule::ConditionConjunction(
123 LifecycleRule::MaxAge(30),
124 LifecycleRule::MatchesStorageClassStandard()),
125 LifecycleRule::Delete());
126 desired_state.set_storage_class(storage_class::Standard())
127 .set_lifecycle(BucketLifecycle{{rule}})
128 .set_website(BucketWebsite{"index.html", "404.html"});
129
130 StatusOr<BucketMetadata> patched =
131 client->PatchBucket(bucket_name, *updated_meta, desired_state);
132 ASSERT_STATUS_OK(patched);
133 EXPECT_EQ(storage_class::Standard(), patched->storage_class());
134 EXPECT_EQ(1, patched->lifecycle().rule.size());
135
136 // Patch the metadata again, this time remove billing and website settings.
137 patched = client->PatchBucket(
138 bucket_name, BucketMetadataPatchBuilder().ResetWebsite().ResetBilling());
139 ASSERT_STATUS_OK(patched);
140 EXPECT_FALSE(patched->has_billing());
141 EXPECT_FALSE(patched->has_website());
142
143 auto status = client->DeleteBucket(bucket_name);
144 ASSERT_STATUS_OK(status);
145 EXPECT_THAT(list_bucket_names(), Not(Contains(bucket_name)));
146 }
147
TEST_F(BucketIntegrationTest,CreatePredefinedAcl)148 TEST_F(BucketIntegrationTest, CreatePredefinedAcl) {
149 std::vector<PredefinedAcl> test_values{
150 PredefinedAcl::AuthenticatedRead(), PredefinedAcl::Private(),
151 PredefinedAcl::ProjectPrivate(), PredefinedAcl::PublicRead(),
152 PredefinedAcl::PublicReadWrite(),
153 };
154
155 StatusOr<Client> client = MakeBucketIntegrationTestClient();
156 ASSERT_STATUS_OK(client);
157 for (auto const& acl : test_values) {
158 SCOPED_TRACE(std::string("Testing with ") +
159 acl.well_known_parameter_name() + "=" + acl.value());
160 std::string bucket_name = MakeRandomBucketName();
161
162 auto metadata = client->CreateBucketForProject(
163 bucket_name, project_id_, BucketMetadata(), PredefinedAcl(acl));
164 ASSERT_STATUS_OK(metadata);
165 EXPECT_EQ(bucket_name, metadata->name());
166
167 // Wait at least 2 seconds before trying to create / delete another bucket.
168 if (!UsingEmulator()) std::this_thread::sleep_for(std::chrono::seconds(2));
169
170 auto status = client->DeleteBucket(bucket_name);
171 ASSERT_STATUS_OK(status);
172
173 // Wait at least 2 seconds before trying to create / delete another bucket.
174 if (!UsingEmulator()) std::this_thread::sleep_for(std::chrono::seconds(2));
175 }
176 }
177
TEST_F(BucketIntegrationTest,CreatePredefinedDefaultObjectAcl)178 TEST_F(BucketIntegrationTest, CreatePredefinedDefaultObjectAcl) {
179 std::vector<PredefinedDefaultObjectAcl> test_values{
180 PredefinedDefaultObjectAcl::AuthenticatedRead(),
181 PredefinedDefaultObjectAcl::BucketOwnerFullControl(),
182 PredefinedDefaultObjectAcl::BucketOwnerRead(),
183 PredefinedDefaultObjectAcl::Private(),
184 PredefinedDefaultObjectAcl::ProjectPrivate(),
185 PredefinedDefaultObjectAcl::PublicRead(),
186 };
187
188 StatusOr<Client> client = MakeBucketIntegrationTestClient();
189 ASSERT_STATUS_OK(client);
190 for (auto const& acl : test_values) {
191 SCOPED_TRACE(std::string("Testing with ") +
192 acl.well_known_parameter_name() + "=" + acl.value());
193 std::string bucket_name = MakeRandomBucketName();
194
195 auto metadata = client->CreateBucketForProject(
196 bucket_name, project_id_, BucketMetadata(),
197 PredefinedDefaultObjectAcl(acl));
198 ASSERT_STATUS_OK(metadata);
199 EXPECT_EQ(bucket_name, metadata->name());
200
201 // Wait at least 2 seconds before trying to create / delete another bucket.
202 if (!UsingEmulator()) std::this_thread::sleep_for(std::chrono::seconds(2));
203
204 auto status = client->DeleteBucket(bucket_name);
205 ASSERT_STATUS_OK(status);
206
207 // Wait at least 2 seconds before trying to create / delete another bucket.
208 if (!UsingEmulator()) std::this_thread::sleep_for(std::chrono::seconds(2));
209 }
210 }
211
TEST_F(BucketIntegrationTest,PatchLifecycleConditions)212 TEST_F(BucketIntegrationTest, PatchLifecycleConditions) {
213 std::vector<LifecycleRuleCondition> test_values{
214 LifecycleRule::MaxAge(30),
215 LifecycleRule::CreatedBefore(absl::CivilDay(2020, 7, 26)),
216 LifecycleRule::IsLive(false),
217 LifecycleRule::MatchesStorageClassArchive(),
218 LifecycleRule::MatchesStorageClasses(
219 {storage_class::Standard(), storage_class::Nearline()}),
220 LifecycleRule::MatchesStorageClassStandard(),
221 // Skip this one because it requires creating a regional bucket (the
222 // default is multi-regional US), and that felt like too much of a hassle
223 // LifecycleRule::MatchesStorageClassRegional(),
224 LifecycleRule::MatchesStorageClassMultiRegional(),
225 LifecycleRule::MatchesStorageClassNearline(),
226 LifecycleRule::MatchesStorageClassColdline(),
227 LifecycleRule::MatchesStorageClassDurableReducedAvailability(),
228 };
229
230 StatusOr<Client> client = MakeBucketIntegrationTestClient();
231 ASSERT_STATUS_OK(client);
232 std::string bucket_name = MakeRandomBucketName();
233
234 auto original = client->CreateBucketForProject(bucket_name, project_id_,
235 BucketMetadata{});
236 ASSERT_STATUS_OK(original);
237 EXPECT_EQ(bucket_name, original->name());
238
239 for (auto const& condition : test_values) {
240 std::ostringstream os;
241 os << "testing with " << condition;
242 auto const str = std::move(os).str();
243 SCOPED_TRACE(str);
244
245 auto updated = client->PatchBucket(
246 bucket_name, BucketMetadataPatchBuilder{}.SetLifecycle({{LifecycleRule{
247 condition, LifecycleRule::Delete()}}}));
248 // We do not use an ASSERT_STATUS_OK() here because we want to continue and
249 // delete the temporary bucket.
250 EXPECT_STATUS_OK(updated);
251 if (updated) {
252 EXPECT_TRUE(updated->has_lifecycle()) << "updated = " << *updated;
253 }
254 }
255
256 auto status = client->DeleteBucket(bucket_name);
257 ASSERT_STATUS_OK(status);
258 }
259
TEST_F(BucketIntegrationTest,FullPatch)260 TEST_F(BucketIntegrationTest, FullPatch) {
261 std::string bucket_name = MakeRandomBucketName();
262 StatusOr<Client> client = MakeBucketIntegrationTestClient();
263 ASSERT_STATUS_OK(client);
264
265 // We need to have an available bucket for logging ...
266 std::string logging_name = MakeRandomBucketName();
267 StatusOr<BucketMetadata> const logging_meta = client->CreateBucketForProject(
268 logging_name, project_id_, BucketMetadata(), PredefinedAcl("private"),
269 PredefinedDefaultObjectAcl("projectPrivate"), Projection("noAcl"));
270 ASSERT_STATUS_OK(logging_meta);
271 EXPECT_EQ(logging_name, logging_meta->name());
272
273 // Wait at least 2 seconds before trying to create / delete another bucket.
274 if (!UsingEmulator()) std::this_thread::sleep_for(std::chrono::seconds(2));
275 // Create a Bucket, use the default settings for most fields, except the
276 // storage class and location. Fetch the full attributes of the bucket.
277 StatusOr<BucketMetadata> const insert_meta = client->CreateBucketForProject(
278 bucket_name, project_id_,
279 BucketMetadata().set_location("US").set_storage_class(
280 storage_class::Standard()),
281 PredefinedAcl("private"), PredefinedDefaultObjectAcl("projectPrivate"),
282 Projection("full"));
283 ASSERT_STATUS_OK(insert_meta);
284 EXPECT_EQ(bucket_name, insert_meta->name());
285
286 // Patch every possible field in the metadata, to verify they work.
287 BucketMetadata desired_state = *insert_meta;
288 // acl()
289 desired_state.mutable_acl().push_back(BucketAccessControl()
290 .set_entity("allAuthenticatedUsers")
291 .set_role("READER"));
292
293 // billing()
294 if (!desired_state.has_billing()) {
295 desired_state.set_billing(BucketBilling(false));
296 } else {
297 desired_state.set_billing(
298 BucketBilling(!desired_state.billing().requester_pays));
299 }
300
301 // cors()
302 desired_state.mutable_cors().push_back(CorsEntry{86400, {"GET"}, {}, {}});
303
304 // default_acl()
305 desired_state.mutable_default_acl().push_back(
306 ObjectAccessControl()
307 .set_entity("allAuthenticatedUsers")
308 .set_role("READER"));
309
310 // encryption()
311 // TODO(#1003) - need a valid KMS entry to set the encryption.
312
313 // iam_configuration() - skipped, cannot set both ACL and iam_configuration in
314 // the same bucket.
315
316 // labels()
317 desired_state.mutable_labels().emplace("test-label", "testing-full-patch");
318
319 // lifecycle()
320 LifecycleRule rule(LifecycleRule::ConditionConjunction(
321 LifecycleRule::MaxAge(30),
322 LifecycleRule::MatchesStorageClassStandard()),
323 LifecycleRule::Delete());
324 desired_state.set_lifecycle(BucketLifecycle{{rule}});
325
326 // logging()
327 if (desired_state.has_logging()) {
328 desired_state.reset_logging();
329 } else {
330 desired_state.set_logging(BucketLogging{logging_name, "test-log"});
331 }
332
333 // storage_class()
334 desired_state.set_storage_class(storage_class::Coldline());
335
336 // versioning()
337 if (!desired_state.has_versioning()) {
338 desired_state.enable_versioning();
339 } else {
340 desired_state.reset_versioning();
341 }
342
343 // website()
344 if (desired_state.has_website()) {
345 desired_state.reset_website();
346 } else {
347 desired_state.set_website(BucketWebsite{"index.html", "404.html"});
348 }
349
350 StatusOr<BucketMetadata> patched =
351 client->PatchBucket(bucket_name, *insert_meta, desired_state);
352 ASSERT_STATUS_OK(patched);
353 // acl() - cannot compare for equality because many fields are updated with
354 // unknown values (entity_id, etag, etc)
355 EXPECT_THAT(AclEntityNames(patched->acl()),
356 ContainsOnce("allAuthenticatedUsers"));
357
358 // billing()
359 EXPECT_EQ(desired_state.billing_as_optional(),
360 patched->billing_as_optional());
361
362 // cors()
363 EXPECT_EQ(desired_state.cors(), patched->cors());
364
365 // default_acl() - cannot compare for equality because many fields are updated
366 // with unknown values (entity_id, etag, etc)
367 EXPECT_THAT(AclEntityNames(patched->default_acl()),
368 ContainsOnce("allAuthenticatedUsers"));
369
370 // encryption() - TODO(#1003) - verify the key was correctly used.
371
372 // lifecycle()
373 EXPECT_EQ(desired_state.lifecycle_as_optional(),
374 patched->lifecycle_as_optional());
375
376 // location()
377 EXPECT_EQ(desired_state.location(), patched->location());
378
379 // logging()
380 EXPECT_EQ(desired_state.logging_as_optional(),
381 patched->logging_as_optional());
382
383 // storage_class()
384 EXPECT_EQ(desired_state.storage_class(), patched->storage_class());
385
386 // versioning()
387 EXPECT_EQ(desired_state.versioning(), patched->versioning());
388
389 // website()
390 EXPECT_EQ(desired_state.website_as_optional(),
391 patched->website_as_optional());
392
393 auto status = client->DeleteBucket(bucket_name);
394 ASSERT_STATUS_OK(status);
395 // Wait at least 2 seconds before trying to create / delete another bucket.
396 if (!UsingEmulator()) std::this_thread::sleep_for(std::chrono::seconds(2));
397 status = client->DeleteBucket(logging_name);
398 ASSERT_STATUS_OK(status);
399 }
400
401 // @test Verify that we can set the iam_configuration() in a Bucket.
TEST_F(BucketIntegrationTest,BucketPolicyOnlyPatch)402 TEST_F(BucketIntegrationTest, BucketPolicyOnlyPatch) {
403 std::string bucket_name = MakeRandomBucketName();
404 StatusOr<Client> client = MakeBucketIntegrationTestClient();
405 ASSERT_STATUS_OK(client);
406
407 // Create a Bucket, use the default settings for all fields. Fetch the full
408 // attributes of the bucket.
409 StatusOr<BucketMetadata> const insert_meta = client->CreateBucketForProject(
410 bucket_name, project_id_, BucketMetadata(), PredefinedAcl("private"),
411 PredefinedDefaultObjectAcl("projectPrivate"), Projection("full"));
412 ASSERT_STATUS_OK(insert_meta);
413 EXPECT_EQ(bucket_name, insert_meta->name());
414
415 // Patch the iam_configuration().
416 BucketMetadata desired_state = *insert_meta;
417 BucketIamConfiguration iam_configuration;
418 iam_configuration.bucket_policy_only = BucketPolicyOnly{true, {}};
419 desired_state.set_iam_configuration(std::move(iam_configuration));
420
421 StatusOr<BucketMetadata> patched =
422 client->PatchBucket(bucket_name, *insert_meta, desired_state);
423 ASSERT_STATUS_OK(patched);
424
425 ASSERT_TRUE(patched->has_iam_configuration()) << "patched=" << *patched;
426 ASSERT_TRUE(patched->iam_configuration().bucket_policy_only)
427 << "patched=" << *patched;
428
429 auto status = client->DeleteBucket(bucket_name);
430 ASSERT_STATUS_OK(status);
431 }
432
433 // @test Verify that we can set the iam_configuration() in a Bucket.
TEST_F(BucketIntegrationTest,UniformBucketLevelAccessPatch)434 TEST_F(BucketIntegrationTest, UniformBucketLevelAccessPatch) {
435 std::string bucket_name = MakeRandomBucketName();
436 StatusOr<Client> client = MakeIntegrationTestClient();
437 ASSERT_STATUS_OK(client);
438
439 // Create a Bucket, use the default settings for all fields. Fetch the full
440 // attributes of the bucket.
441 StatusOr<BucketMetadata> const insert_meta = client->CreateBucketForProject(
442 bucket_name, project_id_, BucketMetadata(), PredefinedAcl("private"),
443 PredefinedDefaultObjectAcl("projectPrivate"), Projection("full"));
444 ASSERT_STATUS_OK(insert_meta);
445 EXPECT_EQ(bucket_name, insert_meta->name());
446
447 // Patch the iam_configuration().
448 BucketMetadata desired_state = *insert_meta;
449 BucketIamConfiguration iam_configuration;
450 iam_configuration.uniform_bucket_level_access =
451 UniformBucketLevelAccess{true, {}};
452 desired_state.set_iam_configuration(std::move(iam_configuration));
453
454 StatusOr<BucketMetadata> patched =
455 client->PatchBucket(bucket_name, *insert_meta, desired_state);
456 ASSERT_STATUS_OK(patched);
457
458 ASSERT_TRUE(patched->has_iam_configuration()) << "patched=" << *patched;
459 ASSERT_TRUE(patched->iam_configuration().uniform_bucket_level_access)
460 << "patched=" << *patched;
461
462 auto status = client->DeleteBucket(bucket_name);
463 ASSERT_STATUS_OK(status);
464 }
465
TEST_F(BucketIntegrationTest,GetMetadata)466 TEST_F(BucketIntegrationTest, GetMetadata) {
467 StatusOr<Client> client = MakeIntegrationTestClient();
468 ASSERT_STATUS_OK(client);
469
470 auto metadata = client->GetBucketMetadata(bucket_name_);
471 ASSERT_STATUS_OK(metadata);
472 EXPECT_EQ(bucket_name_, metadata->name());
473 EXPECT_EQ(bucket_name_, metadata->id());
474 EXPECT_EQ("storage#bucket", metadata->kind());
475 }
476
TEST_F(BucketIntegrationTest,GetMetadataFields)477 TEST_F(BucketIntegrationTest, GetMetadataFields) {
478 StatusOr<Client> client = MakeIntegrationTestClient();
479 ASSERT_STATUS_OK(client);
480
481 auto metadata = client->GetBucketMetadata(bucket_name_, Fields("name"));
482 ASSERT_STATUS_OK(metadata);
483 EXPECT_EQ(bucket_name_, metadata->name());
484 EXPECT_TRUE(metadata->id().empty());
485 EXPECT_TRUE(metadata->kind().empty());
486 }
487
TEST_F(BucketIntegrationTest,GetMetadataIfMetagenerationMatchSuccess)488 TEST_F(BucketIntegrationTest, GetMetadataIfMetagenerationMatchSuccess) {
489 StatusOr<Client> client = MakeIntegrationTestClient();
490 ASSERT_STATUS_OK(client);
491
492 auto metadata = client->GetBucketMetadata(bucket_name_);
493 ASSERT_STATUS_OK(metadata);
494 EXPECT_EQ(bucket_name_, metadata->name());
495 EXPECT_EQ(bucket_name_, metadata->id());
496 EXPECT_EQ("storage#bucket", metadata->kind());
497
498 auto metadata2 = client->GetBucketMetadata(
499 bucket_name_, storage::Projection("noAcl"),
500 storage::IfMetagenerationMatch(metadata->metageneration()));
501 ASSERT_STATUS_OK(metadata2);
502 EXPECT_EQ(*metadata2, *metadata);
503 }
504
TEST_F(BucketIntegrationTest,GetMetadataIfMetagenerationNotMatchFailure)505 TEST_F(BucketIntegrationTest, GetMetadataIfMetagenerationNotMatchFailure) {
506 StatusOr<Client> client = MakeIntegrationTestClient();
507 ASSERT_STATUS_OK(client);
508
509 auto metadata = client->GetBucketMetadata(bucket_name_);
510 ASSERT_STATUS_OK(metadata);
511 EXPECT_EQ(bucket_name_, metadata->name());
512 EXPECT_EQ(bucket_name_, metadata->id());
513 EXPECT_EQ("storage#bucket", metadata->kind());
514
515 auto metadata2 = client->GetBucketMetadata(
516 bucket_name_, storage::Projection("noAcl"),
517 storage::IfMetagenerationNotMatch(metadata->metageneration()));
518 EXPECT_FALSE(metadata2.ok()) << "metadata=" << *metadata2;
519 }
520
TEST_F(BucketIntegrationTest,AccessControlCRUD)521 TEST_F(BucketIntegrationTest, AccessControlCRUD) {
522 std::string bucket_name = MakeRandomBucketName();
523 StatusOr<Client> client = MakeBucketIntegrationTestClient();
524 ASSERT_STATUS_OK(client);
525
526 // Create a new bucket to run the test, with the "private" PredefinedAcl so
527 // we know what the contents of the ACL will be.
528 auto meta = client->CreateBucketForProject(
529 bucket_name, project_id_, BucketMetadata(), PredefinedAcl("private"),
530 Projection("full"));
531 ASSERT_STATUS_OK(meta);
532
533 auto entity_name = MakeEntityName();
534
535 ASSERT_FALSE(meta->acl().empty())
536 << "Test aborted. Empty ACL returned from newly created bucket <"
537 << bucket_name << "> even though we requested the <full> projection.";
538 ASSERT_THAT(AclEntityNames(meta->acl()), Not(Contains(entity_name)))
539 << "Test aborted. The bucket <" << bucket_name << "> has <" << entity_name
540 << "> in its ACL. This is unexpected because the bucket was just"
541 << " created with a predefine ACL which should preclude this result.";
542
543 StatusOr<BucketAccessControl> result =
544 client->CreateBucketAcl(bucket_name, entity_name, "OWNER");
545 ASSERT_STATUS_OK(result);
546 EXPECT_EQ("OWNER", result->role());
547
548 StatusOr<std::vector<BucketAccessControl>> current_acl =
549 client->ListBucketAcl(bucket_name);
550 ASSERT_STATUS_OK(current_acl);
551 EXPECT_FALSE(current_acl->empty());
552 // Search using the entity name returned by the request, because we use
553 // 'project-editors-<project_id>' this different than the original entity
554 // name, the server "translates" the project id to a project number.
555 EXPECT_THAT(AclEntityNames(*current_acl), ContainsOnce(result->entity()));
556
557 StatusOr<BucketAccessControl> get_result =
558 client->GetBucketAcl(bucket_name, entity_name);
559 ASSERT_STATUS_OK(get_result);
560 EXPECT_EQ(*get_result, *result);
561
562 BucketAccessControl new_acl = *get_result;
563 new_acl.set_role("READER");
564 auto updated_result = client->UpdateBucketAcl(bucket_name, new_acl);
565 ASSERT_STATUS_OK(updated_result);
566 EXPECT_EQ("READER", updated_result->role());
567
568 get_result = client->GetBucketAcl(bucket_name, entity_name);
569 ASSERT_STATUS_OK(get_result);
570 EXPECT_EQ(*get_result, *updated_result);
571
572 new_acl = *get_result;
573 new_acl.set_role("OWNER");
574 // Because this is a freshly created bucket, with a random name, we do not
575 // worry about implementing optimistic concurrency control.
576 get_result =
577 client->PatchBucketAcl(bucket_name, entity_name, *get_result, new_acl);
578 ASSERT_STATUS_OK(get_result);
579 EXPECT_EQ(get_result->role(), new_acl.role());
580
581 auto status = client->DeleteBucketAcl(bucket_name, entity_name);
582 ASSERT_STATUS_OK(status);
583
584 current_acl = client->ListBucketAcl(bucket_name);
585 ASSERT_STATUS_OK(current_acl);
586 EXPECT_THAT(AclEntityNames(*current_acl), Not(Contains(result->entity())));
587
588 status = client->DeleteBucket(bucket_name);
589 ASSERT_STATUS_OK(status);
590 }
591
TEST_F(BucketIntegrationTest,DefaultObjectAccessControlCRUD)592 TEST_F(BucketIntegrationTest, DefaultObjectAccessControlCRUD) {
593 std::string bucket_name = MakeRandomBucketName();
594 StatusOr<Client> client = MakeBucketIntegrationTestClient();
595 ASSERT_STATUS_OK(client);
596
597 // Create a new bucket to run the test, with the "private"
598 // PredefinedDefaultObjectAcl, that way we can predict the the contents of the
599 // ACL.
600 auto meta = client->CreateBucketForProject(
601 bucket_name, project_id_, BucketMetadata(),
602 PredefinedDefaultObjectAcl("projectPrivate"), Projection("full"));
603 ASSERT_STATUS_OK(meta);
604
605 auto entity_name = MakeEntityName();
606
607 ASSERT_FALSE(meta->default_acl().empty())
608 << "Test aborted. Empty ACL returned from newly created bucket <"
609 << bucket_name << "> even though we requested the <full> projection.";
610 ASSERT_THAT(AclEntityNames(meta->default_acl()), Not(Contains(entity_name)))
611 << "Test aborted. The bucket <" << bucket_name << "> has <" << entity_name
612 << "> in its ACL. This is unexpected because the bucket was just"
613 << " created with a predefine ACL which should preclude this result.";
614
615 StatusOr<ObjectAccessControl> result =
616 client->CreateDefaultObjectAcl(bucket_name, entity_name, "OWNER");
617 ASSERT_STATUS_OK(result);
618 EXPECT_EQ("OWNER", result->role());
619
620 auto current_acl = client->ListDefaultObjectAcl(bucket_name);
621 ASSERT_STATUS_OK(current_acl);
622 EXPECT_FALSE(current_acl->empty());
623 // Search using the entity name returned by the request, because we use
624 // 'project-editors-<project_id_>' this different than the original entity
625 // name, the server "translates" the project id to a project number.
626 EXPECT_THAT(AclEntityNames(meta->default_acl()),
627 ContainsOnce(result->entity()));
628
629 auto get_result = client->GetDefaultObjectAcl(bucket_name, entity_name);
630 ASSERT_STATUS_OK(get_result);
631 EXPECT_EQ(*get_result, *result);
632
633 ObjectAccessControl new_acl = *get_result;
634 new_acl.set_role("READER");
635 auto updated_result = client->UpdateDefaultObjectAcl(bucket_name, new_acl);
636 ASSERT_STATUS_OK(updated_result);
637
638 EXPECT_EQ(updated_result->role(), "READER");
639 get_result = client->GetDefaultObjectAcl(bucket_name, entity_name);
640 EXPECT_EQ(*get_result, *updated_result);
641
642 new_acl = *get_result;
643 new_acl.set_role("OWNER");
644 get_result =
645 client->PatchDefaultObjectAcl(bucket_name, entity_name, *get_result,
646 new_acl, IfMatchEtag(get_result->etag()));
647 ASSERT_STATUS_OK(get_result);
648 EXPECT_EQ(get_result->role(), new_acl.role());
649
650 auto status = client->DeleteDefaultObjectAcl(bucket_name, entity_name);
651 EXPECT_STATUS_OK(status);
652
653 current_acl = client->ListDefaultObjectAcl(bucket_name);
654 ASSERT_STATUS_OK(current_acl);
655 EXPECT_THAT(AclEntityNames(meta->default_acl()), Not(Contains(entity_name)));
656
657 status = client->DeleteBucket(bucket_name);
658 ASSERT_STATUS_OK(status);
659 }
660
TEST_F(BucketIntegrationTest,NotificationsCRUD)661 TEST_F(BucketIntegrationTest, NotificationsCRUD) {
662 std::string bucket_name = MakeRandomBucketName();
663 StatusOr<Client> client = MakeBucketIntegrationTestClient();
664 ASSERT_STATUS_OK(client);
665
666 // Create a new bucket to run the test.
667 auto meta = client->CreateBucketForProject(bucket_name, project_id_,
668 BucketMetadata());
669 ASSERT_STATUS_OK(meta);
670
671 auto notification_ids = [&client, bucket_name] {
672 std::vector<std::string> ids;
673 auto list = client->ListNotifications(bucket_name);
674 EXPECT_STATUS_OK(list);
675 for (auto const& notification : *list) ids.push_back(notification.id());
676 return ids;
677 };
678 ASSERT_TRUE(notification_ids().empty())
679 << "Test aborted. Non-empty notification list returned from newly"
680 << " created bucket <" << bucket_name
681 << ">. This is unexpected because the bucket name is chosen at random.";
682
683 auto create = client->CreateNotification(
684 bucket_name, topic_name_, payload_format::JsonApiV1(),
685 NotificationMetadata().append_event_type(event_type::ObjectFinalize()));
686 ASSERT_STATUS_OK(create);
687
688 EXPECT_EQ(payload_format::JsonApiV1(), create->payload_format());
689 EXPECT_THAT(create->topic(), HasSubstr(topic_name_));
690 EXPECT_THAT(notification_ids(), ContainsOnce(create->id()))
691 << "create=" << *create;
692
693 auto get = client->GetNotification(bucket_name, create->id());
694 ASSERT_STATUS_OK(get);
695 EXPECT_EQ(*create, *get);
696
697 auto status = client->DeleteNotification(bucket_name, create->id());
698 ASSERT_STATUS_OK(status);
699 EXPECT_THAT(notification_ids(), Not(Contains(create->id())))
700 << "create=" << *create;
701
702 status = client->DeleteBucket(bucket_name);
703 ASSERT_STATUS_OK(status);
704 }
705
TEST_F(BucketIntegrationTest,IamCRUD)706 TEST_F(BucketIntegrationTest, IamCRUD) {
707 std::string bucket_name = MakeRandomBucketName();
708 StatusOr<Client> client = MakeBucketIntegrationTestClient();
709 ASSERT_STATUS_OK(client);
710
711 // Create a new bucket to run the test.
712 auto meta = client->CreateBucketForProject(bucket_name, project_id_,
713 BucketMetadata());
714 ASSERT_STATUS_OK(meta);
715
716 StatusOr<IamPolicy> policy = client->GetBucketIamPolicy(bucket_name);
717 ASSERT_STATUS_OK(policy);
718 auto const& bindings = policy->bindings;
719 // There must always be at least an OWNER for the Bucket.
720 ASSERT_FALSE(bindings.end() ==
721 bindings.find("roles/storage.legacyBucketOwner"));
722
723 StatusOr<std::vector<BucketAccessControl>> acl =
724 client->ListBucketAcl(bucket_name);
725 ASSERT_STATUS_OK(acl);
726 // Unfortunately we cannot compare the values in the ACL to the values in the
727 // IamPolicy directly. The ids for entities have different formats, for
728 // example: in ACL 'project-editors-123456789' and in IAM
729 // 'projectEditors:my-project'. We can compare the counts though:
730 std::set<std::string> expected_owners;
731 for (auto const& entry : *acl) {
732 if (entry.role() == "OWNER") {
733 expected_owners.insert(entry.entity());
734 }
735 }
736 std::set<std::string> actual_owners =
737 bindings.at("roles/storage.legacyBucketOwner");
738 EXPECT_EQ(expected_owners.size(), actual_owners.size());
739
740 IamPolicy update = *policy;
741 update.bindings.AddMember("roles/storage.objectViewer",
742 "allAuthenticatedUsers");
743
744 StatusOr<IamPolicy> updated_policy =
745 client->SetBucketIamPolicy(bucket_name, update);
746 ASSERT_STATUS_OK(updated_policy);
747 EXPECT_EQ(update.bindings, updated_policy->bindings);
748 EXPECT_NE(update.etag, updated_policy->etag);
749
750 std::vector<std::string> expected_permissions{
751 "storage.objects.list", "storage.objects.get", "storage.objects.delete"};
752 StatusOr<std::vector<std::string>> actual_permissions =
753 client->TestBucketIamPermissions(bucket_name, expected_permissions);
754 ASSERT_STATUS_OK(actual_permissions);
755 EXPECT_THAT(*actual_permissions, ElementsAreArray(expected_permissions));
756
757 auto status = client->DeleteBucket(bucket_name);
758 ASSERT_STATUS_OK(status);
759 }
760
TEST_F(BucketIntegrationTest,NativeIamCRUD)761 TEST_F(BucketIntegrationTest, NativeIamCRUD) {
762 std::string bucket_name = MakeRandomBucketName();
763 StatusOr<Client> client = MakeBucketIntegrationTestClient();
764 ASSERT_STATUS_OK(client);
765
766 // Create a new bucket to run the test.
767 auto meta = client->CreateBucketForProject(bucket_name, project_id_,
768 BucketMetadata());
769 ASSERT_STATUS_OK(meta);
770
771 StatusOr<NativeIamPolicy> policy =
772 client->GetNativeBucketIamPolicy(bucket_name);
773 ASSERT_STATUS_OK(policy);
774 auto const& bindings = policy->bindings();
775 // There must always be at least an OWNER for the Bucket.
776 auto owner_it = std::find_if(
777 bindings.begin(), bindings.end(), [](NativeIamBinding const& binding) {
778 return binding.role() == "roles/storage.legacyBucketOwner";
779 });
780 ASSERT_NE(bindings.end(), owner_it);
781
782 StatusOr<std::vector<BucketAccessControl>> acl =
783 client->ListBucketAcl(bucket_name);
784 ASSERT_STATUS_OK(acl);
785 // Unfortunately we cannot compare the values in the ACL to the values in the
786 // IamPolicy directly. The ids for entities have different formats, for
787 // example: in ACL 'project-editors-123456789' and in IAM
788 // 'projectEditors:my-project'. We can compare the counts though:
789 std::set<std::string> expected_owners;
790 for (auto const& entry : *acl) {
791 if (entry.role() == "OWNER") {
792 expected_owners.insert(entry.entity());
793 }
794 }
795 std::set<std::string> actual_owners = std::accumulate(
796 bindings.begin(), bindings.end(), std::set<std::string>(),
797 [](std::set<std::string> acc, NativeIamBinding const& binding) {
798 if (binding.role() == "roles/storage.legacyBucketOwner") {
799 acc.insert(binding.members().begin(), binding.members().end());
800 }
801 return acc;
802 });
803 EXPECT_EQ(expected_owners.size(), actual_owners.size());
804
805 NativeIamPolicy update = *policy;
806 bool role_updated = false;
807 for (auto& binding : update.bindings()) {
808 if (binding.role() != "roles/storage.objectViewer") {
809 continue;
810 }
811 role_updated = true;
812 auto& members = binding.members();
813 if (std::find(members.begin(), members.end(), "allAuthenticatedUsers") ==
814 members.end()) {
815 members.emplace_back("allAuthenticatedUsers");
816 }
817 }
818 if (!role_updated) {
819 update.bindings().emplace_back(NativeIamBinding(
820 "roles/storage.objectViewer", {"allAuthenticatedUsers"}));
821 }
822
823 StatusOr<NativeIamPolicy> updated_policy =
824 client->SetNativeBucketIamPolicy(bucket_name, update);
825 ASSERT_STATUS_OK(updated_policy);
826
827 std::vector<std::string> expected_permissions{
828 "storage.objects.list", "storage.objects.get", "storage.objects.delete"};
829 StatusOr<std::vector<std::string>> actual_permissions =
830 client->TestBucketIamPermissions(bucket_name, expected_permissions);
831 ASSERT_STATUS_OK(actual_permissions);
832 EXPECT_THAT(*actual_permissions, ElementsAreArray(expected_permissions));
833
834 auto status = client->DeleteBucket(bucket_name);
835 ASSERT_STATUS_OK(status);
836 }
837
TEST_F(BucketIntegrationTest,BucketLock)838 TEST_F(BucketIntegrationTest, BucketLock) {
839 std::string bucket_name = MakeRandomBucketName();
840 StatusOr<Client> client = MakeIntegrationTestClient();
841 ASSERT_STATUS_OK(client);
842
843 // Create a new bucket to run the test.
844 auto meta = client->CreateBucketForProject(bucket_name, project_id_,
845 BucketMetadata());
846 ASSERT_STATUS_OK(meta);
847
848 auto after_setting_retention_policy = client->PatchBucket(
849 bucket_name,
850 BucketMetadataPatchBuilder().SetRetentionPolicy(std::chrono::seconds(30)),
851 IfMetagenerationMatch(meta->metageneration()));
852 ASSERT_STATUS_OK(after_setting_retention_policy);
853
854 auto after_locking = client->LockBucketRetentionPolicy(
855 bucket_name, after_setting_retention_policy->metageneration());
856 ASSERT_STATUS_OK(after_locking);
857
858 ASSERT_TRUE(after_locking->has_retention_policy());
859 ASSERT_TRUE(after_locking->retention_policy().is_locked);
860
861 auto status = client->DeleteBucket(bucket_name);
862 ASSERT_STATUS_OK(status);
863 }
864
TEST_F(BucketIntegrationTest,BucketLockFailure)865 TEST_F(BucketIntegrationTest, BucketLockFailure) {
866 std::string bucket_name = MakeRandomBucketName();
867 StatusOr<Client> client = MakeIntegrationTestClient();
868 ASSERT_STATUS_OK(client);
869
870 // This should fail because the bucket does not exist.
871 StatusOr<BucketMetadata> status =
872 client->LockBucketRetentionPolicy(bucket_name, 42U);
873 EXPECT_FALSE(status.ok());
874 }
875
TEST_F(BucketIntegrationTest,ListFailure)876 TEST_F(BucketIntegrationTest, ListFailure) {
877 StatusOr<Client> client = MakeIntegrationTestClient();
878 ASSERT_STATUS_OK(client);
879
880 // Project IDs must end with a letter or number, test with an invalid ID.
881 auto stream = client->ListBucketsForProject("Invalid-project-id-");
882 auto it = stream.begin();
883 StatusOr<BucketMetadata> metadata = *it;
884 EXPECT_FALSE(metadata.ok()) << "value=" << metadata.value();
885 }
886
TEST_F(BucketIntegrationTest,CreateFailure)887 TEST_F(BucketIntegrationTest, CreateFailure) {
888 StatusOr<Client> client = MakeIntegrationTestClient();
889 ASSERT_STATUS_OK(client);
890
891 // Try to create an invalid bucket (the name should not start with an
892 // uppercase letter), the service (or emulator) will reject the request and
893 // we should report that error correctly. For good measure, make the project
894 // id invalid too.
895 StatusOr<BucketMetadata> meta = client->CreateBucketForProject(
896 "Invalid_Bucket_Name", "Invalid-project-id-", BucketMetadata());
897 ASSERT_FALSE(meta.ok()) << "metadata=" << meta.value();
898 }
899
TEST_F(BucketIntegrationTest,GetFailure)900 TEST_F(BucketIntegrationTest, GetFailure) {
901 StatusOr<Client> client = MakeIntegrationTestClient();
902 ASSERT_STATUS_OK(client);
903 std::string bucket_name = MakeRandomBucketName();
904
905 // Try to get information about a bucket that does not exist, or at least
906 // it is very unlikely to exist, the name is random.
907 auto status = client->GetBucketMetadata(bucket_name);
908 ASSERT_FALSE(status.ok()) << "value=" << status.value();
909 }
910
TEST_F(BucketIntegrationTest,DeleteFailure)911 TEST_F(BucketIntegrationTest, DeleteFailure) {
912 StatusOr<Client> client = MakeIntegrationTestClient();
913 ASSERT_STATUS_OK(client);
914 std::string bucket_name = MakeRandomBucketName();
915
916 // Try to delete a bucket that does not exist, or at least it is very unlikely
917 // to exist, the name is random.
918 auto status = client->DeleteBucket(bucket_name);
919 ASSERT_FALSE(status.ok());
920 }
921
TEST_F(BucketIntegrationTest,UpdateFailure)922 TEST_F(BucketIntegrationTest, UpdateFailure) {
923 StatusOr<Client> client = MakeIntegrationTestClient();
924 ASSERT_STATUS_OK(client);
925 std::string bucket_name = MakeRandomBucketName();
926
927 // Try to update a bucket that does not exist, or at least it is very unlikely
928 // to exist, the name is random.
929 auto status = client->UpdateBucket(bucket_name, BucketMetadata());
930 ASSERT_FALSE(status.ok()) << "value=" << status.value();
931 }
932
TEST_F(BucketIntegrationTest,PatchFailure)933 TEST_F(BucketIntegrationTest, PatchFailure) {
934 StatusOr<Client> client = MakeIntegrationTestClient();
935 ASSERT_STATUS_OK(client);
936 std::string bucket_name = MakeRandomBucketName();
937
938 // Try to update a bucket that does not exist, or at least it is very unlikely
939 // to exist, the name is random.
940 auto status = client->PatchBucket(bucket_name, BucketMetadataPatchBuilder());
941 ASSERT_FALSE(status.ok()) << "value=" << status.value();
942 }
943
TEST_F(BucketIntegrationTest,GetBucketIamPolicyFailure)944 TEST_F(BucketIntegrationTest, GetBucketIamPolicyFailure) {
945 StatusOr<Client> client = MakeIntegrationTestClient();
946 ASSERT_STATUS_OK(client);
947 std::string bucket_name = MakeRandomBucketName();
948
949 // Try to get information about a bucket that does not exist, or at least it
950 // is very unlikely to exist, the name is random.
951 auto policy = client->GetBucketIamPolicy(bucket_name);
952 EXPECT_FALSE(policy.ok()) << "value=" << policy.value();
953 }
954
TEST_F(BucketIntegrationTest,SetBucketIamPolicyFailure)955 TEST_F(BucketIntegrationTest, SetBucketIamPolicyFailure) {
956 StatusOr<Client> client = MakeIntegrationTestClient();
957 ASSERT_STATUS_OK(client);
958 std::string bucket_name = MakeRandomBucketName();
959
960 // Try to set the IAM policy on a bucket that does not exist, or at least it
961 // is very unlikely to exist, the name is random.
962 auto policy = client->SetBucketIamPolicy(bucket_name, IamPolicy{});
963 EXPECT_FALSE(policy.ok()) << "value=" << policy.value();
964 }
965
TEST_F(BucketIntegrationTest,TestBucketIamPermissionsFailure)966 TEST_F(BucketIntegrationTest, TestBucketIamPermissionsFailure) {
967 StatusOr<Client> client = MakeIntegrationTestClient();
968 ASSERT_STATUS_OK(client);
969 std::string bucket_name = MakeRandomBucketName();
970
971 // Try to set the IAM policy on a bucket that does not exist, or at least it
972 // is very unlikely to exist, the name is random.
973 auto items = client->TestBucketIamPermissions(bucket_name, {});
974 EXPECT_FALSE(items.ok()) << "items[0]=" << items.value().front();
975 }
976
TEST_F(BucketIntegrationTest,ListAccessControlFailure)977 TEST_F(BucketIntegrationTest, ListAccessControlFailure) {
978 StatusOr<Client> client = MakeIntegrationTestClient();
979 ASSERT_STATUS_OK(client);
980 std::string bucket_name = MakeRandomBucketName();
981
982 // This operation should fail because the target bucket does not exist.
983 auto list = client->ListBucketAcl(bucket_name);
984 EXPECT_FALSE(list.ok()) << "list[0]=" << list.value().front();
985 }
986
TEST_F(BucketIntegrationTest,CreateAccessControlFailure)987 TEST_F(BucketIntegrationTest, CreateAccessControlFailure) {
988 StatusOr<Client> client = MakeIntegrationTestClient();
989 ASSERT_STATUS_OK(client);
990 std::string bucket_name = MakeRandomBucketName();
991 auto entity_name = MakeEntityName();
992
993 // This operation should fail because the target bucket does not exist.
994 auto acl = client->CreateBucketAcl(bucket_name, entity_name, "READER");
995 EXPECT_FALSE(acl.ok()) << "value=" << acl.value();
996 }
997
TEST_F(BucketIntegrationTest,GetAccessControlFailure)998 TEST_F(BucketIntegrationTest, GetAccessControlFailure) {
999 StatusOr<Client> client = MakeIntegrationTestClient();
1000 ASSERT_STATUS_OK(client);
1001 std::string bucket_name = MakeRandomBucketName();
1002 auto entity_name = MakeEntityName();
1003
1004 // This operation should fail because the target bucket does not exist.
1005 auto acl = client->GetBucketAcl(bucket_name, entity_name);
1006 EXPECT_FALSE(acl.ok()) << "value=" << acl.value();
1007 }
1008
TEST_F(BucketIntegrationTest,UpdateAccessControlFailure)1009 TEST_F(BucketIntegrationTest, UpdateAccessControlFailure) {
1010 StatusOr<Client> client = MakeIntegrationTestClient();
1011 ASSERT_STATUS_OK(client);
1012 std::string bucket_name = MakeRandomBucketName();
1013 auto entity_name = MakeEntityName();
1014
1015 // This operation should fail because the target bucket does not exist.
1016 auto acl = client->UpdateBucketAcl(
1017 bucket_name,
1018 BucketAccessControl().set_entity(entity_name).set_role("READER"));
1019 EXPECT_FALSE(acl.ok()) << "value=" << acl.value();
1020 }
1021
TEST_F(BucketIntegrationTest,PatchAccessControlFailure)1022 TEST_F(BucketIntegrationTest, PatchAccessControlFailure) {
1023 StatusOr<Client> client = MakeIntegrationTestClient();
1024 ASSERT_STATUS_OK(client);
1025 std::string bucket_name = MakeRandomBucketName();
1026 auto entity_name = MakeEntityName();
1027
1028 // This operation should fail because the target bucket does not exist.
1029 auto acl = client->PatchBucketAcl(
1030 bucket_name, entity_name, BucketAccessControl(),
1031 BucketAccessControl().set_entity(entity_name).set_role("READER"));
1032 EXPECT_FALSE(acl.ok()) << "value=" << acl.value();
1033 }
1034
TEST_F(BucketIntegrationTest,DeleteAccessControlFailure)1035 TEST_F(BucketIntegrationTest, DeleteAccessControlFailure) {
1036 StatusOr<Client> client = MakeIntegrationTestClient();
1037 ASSERT_STATUS_OK(client);
1038 std::string bucket_name = MakeRandomBucketName();
1039 auto entity_name = MakeEntityName();
1040
1041 // This operation should fail because the target bucket does not exist.
1042 auto status = client->DeleteBucketAcl(bucket_name, entity_name);
1043 EXPECT_FALSE(status.ok());
1044 }
1045
TEST_F(BucketIntegrationTest,ListDefaultAccessControlFailure)1046 TEST_F(BucketIntegrationTest, ListDefaultAccessControlFailure) {
1047 StatusOr<Client> client = MakeIntegrationTestClient();
1048 ASSERT_STATUS_OK(client);
1049 std::string bucket_name = MakeRandomBucketName();
1050
1051 // This operation should fail because the target bucket does not exist.
1052 auto status = client->ListDefaultObjectAcl(bucket_name).status();
1053 EXPECT_FALSE(status.ok());
1054 }
1055
TEST_F(BucketIntegrationTest,CreateDefaultAccessControlFailure)1056 TEST_F(BucketIntegrationTest, CreateDefaultAccessControlFailure) {
1057 StatusOr<Client> client = MakeIntegrationTestClient();
1058 ASSERT_STATUS_OK(client);
1059 std::string bucket_name = MakeRandomBucketName();
1060 auto entity_name = MakeEntityName();
1061
1062 // This operation should fail because the target bucket does not exist.
1063 auto status =
1064 client->CreateDefaultObjectAcl(bucket_name, entity_name, "READER")
1065 .status();
1066 EXPECT_FALSE(status.ok());
1067 }
1068
TEST_F(BucketIntegrationTest,GetDefaultAccessControlFailure)1069 TEST_F(BucketIntegrationTest, GetDefaultAccessControlFailure) {
1070 StatusOr<Client> client = MakeIntegrationTestClient();
1071 ASSERT_STATUS_OK(client);
1072 std::string bucket_name = MakeRandomBucketName();
1073 auto entity_name = MakeEntityName();
1074
1075 // This operation should fail because the target bucket does not exist.
1076 auto status = client->GetDefaultObjectAcl(bucket_name, entity_name).status();
1077 EXPECT_FALSE(status.ok());
1078 }
1079
TEST_F(BucketIntegrationTest,UpdateDefaultAccessControlFailure)1080 TEST_F(BucketIntegrationTest, UpdateDefaultAccessControlFailure) {
1081 StatusOr<Client> client = MakeIntegrationTestClient();
1082 ASSERT_STATUS_OK(client);
1083 std::string bucket_name = MakeRandomBucketName();
1084 auto entity_name = MakeEntityName();
1085
1086 // This operation should fail because the target bucket does not exist.
1087 auto status =
1088 client
1089 ->UpdateDefaultObjectAcl(
1090 bucket_name,
1091 ObjectAccessControl().set_entity(entity_name).set_role("READER"))
1092 .status();
1093 EXPECT_FALSE(status.ok());
1094 }
1095
TEST_F(BucketIntegrationTest,PatchDefaultAccessControlFailure)1096 TEST_F(BucketIntegrationTest, PatchDefaultAccessControlFailure) {
1097 StatusOr<Client> client = MakeIntegrationTestClient();
1098 ASSERT_STATUS_OK(client);
1099 std::string bucket_name = MakeRandomBucketName();
1100 auto entity_name = MakeEntityName();
1101
1102 // This operation should fail because the target bucket does not exist.
1103 auto status =
1104 client
1105 ->PatchDefaultObjectAcl(
1106 bucket_name, entity_name, ObjectAccessControl(),
1107 ObjectAccessControl().set_entity(entity_name).set_role("READER"))
1108 .status();
1109 EXPECT_FALSE(status.ok());
1110 }
1111
TEST_F(BucketIntegrationTest,DeleteDefaultAccessControlFailure)1112 TEST_F(BucketIntegrationTest, DeleteDefaultAccessControlFailure) {
1113 StatusOr<Client> client = MakeIntegrationTestClient();
1114 ASSERT_STATUS_OK(client);
1115 std::string bucket_name = MakeRandomBucketName();
1116 auto entity_name = MakeEntityName();
1117
1118 // This operation should fail because the target bucket does not exist.
1119 auto status = client->DeleteDefaultObjectAcl(bucket_name, entity_name);
1120 EXPECT_FALSE(status.ok());
1121 }
1122
TEST_F(BucketIntegrationTest,NativeIamWithRequestedPolicyVersion)1123 TEST_F(BucketIntegrationTest, NativeIamWithRequestedPolicyVersion) {
1124 std::string bucket_name = MakeRandomBucketName();
1125 StatusOr<Client> client = MakeIntegrationTestClient();
1126 ASSERT_STATUS_OK(client);
1127
1128 // Create a new bucket to run the test.
1129 BucketMetadata original = BucketMetadata();
1130 BucketIamConfiguration configuration;
1131 configuration.uniform_bucket_level_access =
1132 UniformBucketLevelAccess{true, {}};
1133
1134 original.set_iam_configuration(std::move(configuration));
1135
1136 auto meta =
1137 client->CreateBucketForProject(bucket_name, project_id_, original);
1138 ASSERT_STATUS_OK(meta) << bucket_name;
1139
1140 StatusOr<NativeIamPolicy> policy =
1141 client->GetNativeBucketIamPolicy(bucket_name, RequestedPolicyVersion(1));
1142
1143 ASSERT_STATUS_OK(policy);
1144 ASSERT_EQ(1, policy->version());
1145
1146 auto const& bindings = policy->bindings();
1147 // There must always be at least an OWNER for the Bucket.
1148 auto owner_it = std::find_if(
1149 bindings.begin(), bindings.end(), [](NativeIamBinding const& binding) {
1150 return binding.role() == "roles/storage.legacyBucketOwner";
1151 });
1152 ASSERT_NE(bindings.end(), owner_it);
1153
1154 NativeIamPolicy update = *policy;
1155 bool role_updated = false;
1156 for (auto& binding : update.bindings()) {
1157 if (binding.role() != "roles/storage.objectViewer") {
1158 continue;
1159 }
1160 role_updated = true;
1161
1162 auto& members = binding.members();
1163 if (std::find(members.begin(), members.end(), "allAuthenticatedUsers") ==
1164 members.end()) {
1165 members.emplace_back("serviceAccount:" + service_account_);
1166 }
1167 }
1168 if (!role_updated) {
1169 update.bindings().emplace_back(NativeIamBinding(
1170 "roles/storage.objectViewer", {"serviceAccount:" + service_account_},
1171 NativeExpression(
1172 "request.time < timestamp(\"2019-07-01T00:00:00.000Z\")",
1173 "Expires_July_1_2019", "Expires on July 1, 2019")));
1174 update.set_version(3);
1175 }
1176
1177 StatusOr<NativeIamPolicy> updated_policy =
1178 client->SetNativeBucketIamPolicy(bucket_name, update);
1179 ASSERT_STATUS_OK(updated_policy);
1180
1181 StatusOr<NativeIamPolicy> policy_with_condition =
1182 client->GetNativeBucketIamPolicy(bucket_name, RequestedPolicyVersion(3));
1183 ASSERT_STATUS_OK(policy_with_condition);
1184 ASSERT_EQ(3, policy_with_condition->version());
1185
1186 std::vector<std::string> expected_permissions{
1187 "storage.objects.list", "storage.objects.get", "storage.objects.delete"};
1188 StatusOr<std::vector<std::string>> actual_permissions =
1189 client->TestBucketIamPermissions(bucket_name, expected_permissions);
1190 ASSERT_STATUS_OK(actual_permissions);
1191 EXPECT_THAT(*actual_permissions, ElementsAreArray(expected_permissions));
1192
1193 auto status = client->DeleteBucket(bucket_name);
1194 ASSERT_STATUS_OK(status);
1195 }
1196 } // namespace
1197 } // namespace STORAGE_CLIENT_NS
1198 } // namespace storage
1199 } // namespace cloud
1200 } // namespace google
1201