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