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/internal/object_access_control_parser.h"
17 #include "google/cloud/storage/oauth2/google_credentials.h"
18 #include "google/cloud/storage/retry_policy.h"
19 #include "google/cloud/storage/testing/canonical_errors.h"
20 #include "google/cloud/storage/testing/mock_client.h"
21 #include "google/cloud/storage/testing/retry_tests.h"
22 #include "google/cloud/testing_util/assert_ok.h"
23 #include <gmock/gmock.h>
24 
25 namespace google {
26 namespace cloud {
27 namespace storage {
28 inline namespace STORAGE_CLIENT_NS {
29 namespace {
30 
31 using ::google::cloud::storage::testing::canonical_errors::TransientError;
32 using ::testing::_;
33 using ::testing::Return;
34 using ::testing::ReturnRef;
35 using ms = std::chrono::milliseconds;
36 
37 /**
38  * Test the BucketAccessControls-related functions in storage::Client.
39  */
40 class DefaultObjectAccessControlsTest : public ::testing::Test {
41  protected:
SetUp()42   void SetUp() override {
43     mock_ = std::make_shared<testing::MockClient>();
44     EXPECT_CALL(*mock_, client_options())
45         .WillRepeatedly(ReturnRef(client_options_));
46     client_.reset(new Client{
47         std::shared_ptr<internal::RawClient>(mock_),
48         ExponentialBackoffPolicy(std::chrono::milliseconds(1),
49                                  std::chrono::milliseconds(1), 2.0)});
50   }
TearDown()51   void TearDown() override {
52     client_.reset();
53     mock_.reset();
54   }
55 
56   std::shared_ptr<testing::MockClient> mock_;
57   std::unique_ptr<Client> client_;
58   ClientOptions client_options_ =
59       ClientOptions(oauth2::CreateAnonymousCredentials());
60 };
61 
TEST_F(DefaultObjectAccessControlsTest,ListDefaultObjectAcl)62 TEST_F(DefaultObjectAccessControlsTest, ListDefaultObjectAcl) {
63   std::vector<ObjectAccessControl> expected{
64       internal::ObjectAccessControlParser::FromString(R"""({
65           "bucket": "test-bucket",
66           "entity": "user-test-user-1",
67           "role": "OWNER"
68       })""")
69           .value(),
70       internal::ObjectAccessControlParser::FromString(R"""({
71           "bucket": "test-bucket",
72           "entity": "user-test-user-2",
73           "role": "READER"
74       })""")
75           .value(),
76   };
77 
78   EXPECT_CALL(*mock_, ListDefaultObjectAcl(_))
79       .WillOnce(Return(
80           StatusOr<internal::ListDefaultObjectAclResponse>(TransientError())))
81       .WillOnce([&expected](internal::ListDefaultObjectAclRequest const& r) {
82         EXPECT_EQ("test-bucket", r.bucket_name());
83 
84         return make_status_or(internal::ListDefaultObjectAclResponse{expected});
85       });
86 
87   StatusOr<std::vector<ObjectAccessControl>> actual =
88       client_->ListDefaultObjectAcl("test-bucket");
89   ASSERT_STATUS_OK(actual);
90   EXPECT_EQ(expected, *actual);
91 }
92 
TEST_F(DefaultObjectAccessControlsTest,ListDefaultObjectAclTooManyFailures)93 TEST_F(DefaultObjectAccessControlsTest, ListDefaultObjectAclTooManyFailures) {
94   testing::TooManyFailuresStatusTest<internal::ListDefaultObjectAclResponse>(
95       mock_, EXPECT_CALL(*mock_, ListDefaultObjectAcl(_)),
96       [](Client& client) {
97         return client.ListDefaultObjectAcl("test-bucket-name").status();
98       },
99       "ListDefaultObjectAcl");
100 }
101 
TEST_F(DefaultObjectAccessControlsTest,ListDefaultObjectAclPermanentFailure)102 TEST_F(DefaultObjectAccessControlsTest, ListDefaultObjectAclPermanentFailure) {
103   testing::PermanentFailureStatusTest<internal::ListDefaultObjectAclResponse>(
104       *client_, EXPECT_CALL(*mock_, ListDefaultObjectAcl(_)),
105       [](Client& client) {
106         return client.ListDefaultObjectAcl("test-bucket-name").status();
107       },
108       "ListDefaultObjectAcl");
109 }
110 
TEST_F(DefaultObjectAccessControlsTest,CreateDefaultObjectAcl)111 TEST_F(DefaultObjectAccessControlsTest, CreateDefaultObjectAcl) {
112   auto expected = internal::ObjectAccessControlParser::FromString(R"""({
113           "bucket": "test-bucket",
114           "entity": "user-test-user-1",
115           "role": "READER"
116       })""")
117                       .value();
118 
119   EXPECT_CALL(*mock_, CreateDefaultObjectAcl(_))
120       .WillOnce(Return(StatusOr<ObjectAccessControl>(TransientError())))
121       .WillOnce([&expected](internal::CreateDefaultObjectAclRequest const& r) {
122         EXPECT_EQ("test-bucket", r.bucket_name());
123         EXPECT_EQ("user-test-user-1", r.entity());
124         EXPECT_EQ("READER", r.role());
125 
126         return make_status_or(expected);
127       });
128   StatusOr<ObjectAccessControl> actual = client_->CreateDefaultObjectAcl(
129       "test-bucket", "user-test-user-1", ObjectAccessControl::ROLE_READER());
130   ASSERT_STATUS_OK(actual);
131   // Compare just a few fields because the values for most of the fields are
132   // hard to predict when testing against the production environment.
133   EXPECT_EQ(expected.bucket(), actual->bucket());
134   EXPECT_EQ(expected.entity(), actual->entity());
135   EXPECT_EQ(expected.role(), actual->role());
136 }
137 
TEST_F(DefaultObjectAccessControlsTest,CreateDefaultObjectAclTooManyFailures)138 TEST_F(DefaultObjectAccessControlsTest, CreateDefaultObjectAclTooManyFailures) {
139   testing::TooManyFailuresStatusTest<ObjectAccessControl>(
140       mock_, EXPECT_CALL(*mock_, CreateDefaultObjectAcl(_)),
141       [](Client& client) {
142         return client
143             .CreateDefaultObjectAcl("test-bucket-name", "user-test-user-1",
144                                     "READER")
145             .status();
146       },
147       [](Client& client) {
148         return client
149             .CreateDefaultObjectAcl("test-bucket-name", "user-test-user-1",
150                                     "READER", IfMatchEtag("ABC="))
151             .status();
152       },
153       "CreateDefaultObjectAcl");
154 }
155 
TEST_F(DefaultObjectAccessControlsTest,CreateDefaultObjectAclPermanentFailure)156 TEST_F(DefaultObjectAccessControlsTest,
157        CreateDefaultObjectAclPermanentFailure) {
158   testing::PermanentFailureStatusTest<ObjectAccessControl>(
159       *client_, EXPECT_CALL(*mock_, CreateDefaultObjectAcl(_)),
160       [](Client& client) {
161         return client
162             .CreateDefaultObjectAcl("test-bucket-name", "user-test-user",
163                                     "READER")
164             .status();
165       },
166       "CreateDefaultObjectAcl");
167 }
168 
TEST_F(DefaultObjectAccessControlsTest,DeleteDefaultObjectAcl)169 TEST_F(DefaultObjectAccessControlsTest, DeleteDefaultObjectAcl) {
170   EXPECT_CALL(*mock_, DeleteDefaultObjectAcl(_))
171       .WillOnce(Return(StatusOr<internal::EmptyResponse>(TransientError())))
172       .WillOnce([](internal::DeleteDefaultObjectAclRequest const& r) {
173         EXPECT_EQ("test-bucket", r.bucket_name());
174         EXPECT_EQ("user-test-user", r.entity());
175 
176         return make_status_or(internal::EmptyResponse{});
177       });
178   auto status =
179       client_->DeleteDefaultObjectAcl("test-bucket", "user-test-user");
180   ASSERT_STATUS_OK(status);
181 }
182 
TEST_F(DefaultObjectAccessControlsTest,DeleteDefaultObjectAclTooManyFailures)183 TEST_F(DefaultObjectAccessControlsTest, DeleteDefaultObjectAclTooManyFailures) {
184   testing::TooManyFailuresStatusTest<internal::EmptyResponse>(
185       mock_, EXPECT_CALL(*mock_, DeleteDefaultObjectAcl(_)),
186       [](Client& client) {
187         return client.DeleteDefaultObjectAcl("test-bucket-name",
188                                              "user-test-user-1");
189       },
190       [](Client& client) {
191         return client.DeleteDefaultObjectAcl(
192             "test-bucket-name", "user-test-user-1", IfMatchEtag("ABC="));
193       },
194       "DeleteDefaultObjectAcl");
195 }
196 
TEST_F(DefaultObjectAccessControlsTest,DeleteDefaultObjectAclPermanentFailure)197 TEST_F(DefaultObjectAccessControlsTest,
198        DeleteDefaultObjectAclPermanentFailure) {
199   testing::PermanentFailureStatusTest<internal::EmptyResponse>(
200       *client_, EXPECT_CALL(*mock_, DeleteDefaultObjectAcl(_)),
201       [](Client& client) {
202         return client.DeleteDefaultObjectAcl("test-bucket-name",
203                                              "user-test-user-1");
204       },
205       "DeleteDefaultObjectAcl");
206 }
207 
TEST_F(DefaultObjectAccessControlsTest,GetDefaultObjectAcl)208 TEST_F(DefaultObjectAccessControlsTest, GetDefaultObjectAcl) {
209   ObjectAccessControl expected =
210       internal::ObjectAccessControlParser::FromString(R"""({
211           "bucket": "test-bucket",
212           "entity": "user-test-user-1",
213           "role": "OWNER"
214       })""")
215           .value();
216 
217   EXPECT_CALL(*mock_, GetDefaultObjectAcl(_))
218       .WillOnce(Return(StatusOr<ObjectAccessControl>(TransientError())))
219       .WillOnce([&expected](internal::GetDefaultObjectAclRequest const& r) {
220         EXPECT_EQ("test-bucket", r.bucket_name());
221         EXPECT_EQ("user-test-user-1", r.entity());
222 
223         return make_status_or(expected);
224       });
225   StatusOr<ObjectAccessControl> actual =
226       client_->GetDefaultObjectAcl("test-bucket", "user-test-user-1");
227   ASSERT_STATUS_OK(actual);
228   EXPECT_EQ(expected, *actual);
229 }
230 
TEST_F(DefaultObjectAccessControlsTest,GetDefaultObjectAclTooManyFailures)231 TEST_F(DefaultObjectAccessControlsTest, GetDefaultObjectAclTooManyFailures) {
232   testing::TooManyFailuresStatusTest<ObjectAccessControl>(
233       mock_, EXPECT_CALL(*mock_, GetDefaultObjectAcl(_)),
234       [](Client& client) {
235         return client
236             .GetDefaultObjectAcl("test-bucket-name", "user-test-user-1")
237             .status();
238       },
239       "GetDefaultObjectAcl");
240 }
241 
TEST_F(DefaultObjectAccessControlsTest,GetDefaultObjectAclPermanentFailure)242 TEST_F(DefaultObjectAccessControlsTest, GetDefaultObjectAclPermanentFailure) {
243   testing::PermanentFailureStatusTest<ObjectAccessControl>(
244       *client_, EXPECT_CALL(*mock_, GetDefaultObjectAcl(_)),
245       [](Client& client) {
246         return client
247             .GetDefaultObjectAcl("test-bucket-name", "user-test-user-1")
248             .status();
249       },
250       "GetDefaultObjectAcl");
251 }
252 
TEST_F(DefaultObjectAccessControlsTest,UpdateDefaultObjectAcl)253 TEST_F(DefaultObjectAccessControlsTest, UpdateDefaultObjectAcl) {
254   auto expected = internal::ObjectAccessControlParser::FromString(R"""({
255           "bucket": "test-bucket",
256           "entity": "user-test-user-1",
257           "role": "READER"
258       })""")
259                       .value();
260 
261   EXPECT_CALL(*mock_, UpdateDefaultObjectAcl(_))
262       .WillOnce(Return(StatusOr<ObjectAccessControl>(TransientError())))
263       .WillOnce([&expected](internal::UpdateDefaultObjectAclRequest const& r) {
264         EXPECT_EQ("test-bucket", r.bucket_name());
265         EXPECT_EQ("user-test-user-1", r.entity());
266         EXPECT_EQ("READER", r.role());
267 
268         return make_status_or(expected);
269       });
270   StatusOr<ObjectAccessControl> actual = client_->UpdateDefaultObjectAcl(
271       "test-bucket", ObjectAccessControl()
272                          .set_entity("user-test-user-1")
273                          .set_role(ObjectAccessControl::ROLE_READER()));
274   ASSERT_STATUS_OK(actual);
275   // Compare just a few fields because the values for most of the fields are
276   // hard to predict when testing against the production environment.
277   EXPECT_EQ(expected.bucket(), actual->bucket());
278   EXPECT_EQ(expected.entity(), actual->entity());
279   EXPECT_EQ(expected.role(), actual->role());
280 }
281 
TEST_F(DefaultObjectAccessControlsTest,UpdateDefaultObjectAclTooManyFailures)282 TEST_F(DefaultObjectAccessControlsTest, UpdateDefaultObjectAclTooManyFailures) {
283   testing::TooManyFailuresStatusTest<ObjectAccessControl>(
284       mock_, EXPECT_CALL(*mock_, UpdateDefaultObjectAcl(_)),
285       [](Client& client) {
286         return client
287             .UpdateDefaultObjectAcl("test-bucket-name", ObjectAccessControl())
288             .status();
289       },
290       [](Client& client) {
291         return client
292             .UpdateDefaultObjectAcl("test-bucket-name", ObjectAccessControl(),
293                                     IfMatchEtag("ABC="))
294             .status();
295       },
296       "UpdateDefaultObjectAcl");
297 }
298 
TEST_F(DefaultObjectAccessControlsTest,UpdateDefaultObjectAclPermanentFailure)299 TEST_F(DefaultObjectAccessControlsTest,
300        UpdateDefaultObjectAclPermanentFailure) {
301   testing::PermanentFailureStatusTest<ObjectAccessControl>(
302       *client_, EXPECT_CALL(*mock_, UpdateDefaultObjectAcl(_)),
303       [](Client& client) {
304         return client
305             .UpdateDefaultObjectAcl("test-bucket-name", ObjectAccessControl())
306             .status();
307       },
308       "UpdateDefaultObjectAcl");
309 }
310 
TEST_F(DefaultObjectAccessControlsTest,PatchDefaultObjectAcl)311 TEST_F(DefaultObjectAccessControlsTest, PatchDefaultObjectAcl) {
312   auto result = internal::ObjectAccessControlParser::FromString(R"""({
313           "bucket": "test-bucket",
314           "entity": "user-test-user-1",
315           "role": "OWNER"
316       })""")
317                     .value();
318 
319   EXPECT_CALL(*mock_, PatchDefaultObjectAcl(_))
320       .WillOnce(Return(StatusOr<ObjectAccessControl>(TransientError())))
321       .WillOnce([result](internal::PatchDefaultObjectAclRequest const& r) {
322         EXPECT_EQ("test-bucket", r.bucket_name());
323         EXPECT_EQ("user-test-user-1", r.entity());
324         nlohmann::json expected{{"role", "OWNER"}};
325         auto payload = nlohmann::json::parse(r.payload());
326         EXPECT_EQ(expected, payload);
327 
328         return make_status_or(result);
329       });
330   auto actual = client_->PatchDefaultObjectAcl(
331       "test-bucket", "user-test-user-1",
332       ObjectAccessControlPatchBuilder().set_role("OWNER"));
333   ASSERT_STATUS_OK(actual);
334   EXPECT_EQ(result, *actual);
335 }
336 
TEST_F(DefaultObjectAccessControlsTest,PatchDefaultObjectAclTooManyFailures)337 TEST_F(DefaultObjectAccessControlsTest, PatchDefaultObjectAclTooManyFailures) {
338   testing::TooManyFailuresStatusTest<ObjectAccessControl>(
339       mock_, EXPECT_CALL(*mock_, PatchDefaultObjectAcl(_)),
340       [](Client& client) {
341         return client
342             .PatchDefaultObjectAcl("test-bucket-name", "user-test-user-1",
343                                    ObjectAccessControlPatchBuilder())
344             .status();
345       },
346       [](Client& client) {
347         return client
348             .PatchDefaultObjectAcl("test-bucket-name", "user-test-user-1",
349                                    ObjectAccessControlPatchBuilder(),
350                                    IfMatchEtag("ABC="))
351             .status();
352       },
353       "PatchDefaultObjectAcl");
354 }
355 
TEST_F(DefaultObjectAccessControlsTest,PatchDefaultObjectAclPermanentFailure)356 TEST_F(DefaultObjectAccessControlsTest, PatchDefaultObjectAclPermanentFailure) {
357   testing::PermanentFailureStatusTest<ObjectAccessControl>(
358       *client_, EXPECT_CALL(*mock_, PatchDefaultObjectAcl(_)),
359       [](Client& client) {
360         return client
361             .PatchDefaultObjectAcl("test-bucket-name", "user-test-user-1",
362                                    ObjectAccessControlPatchBuilder())
363             .status();
364       },
365       "PatchDefaultObjectAcl");
366 }
367 
368 }  // namespace
369 }  // namespace STORAGE_CLIENT_NS
370 }  // namespace storage
371 }  // namespace cloud
372 }  // namespace google
373