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