Skip to content

Commit 76a4024

Browse files
authored
feat(GCS+gRPC): implement PatchDefaultObjectAcl() (#9487)
1 parent c674e84 commit 76a4024

3 files changed

Lines changed: 81 additions & 2 deletions

File tree

google/cloud/storage/internal/grpc_client.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -918,8 +918,15 @@ StatusOr<ObjectAccessControl> GrpcClient::UpdateDefaultObjectAcl(
918918
}
919919

920920
StatusOr<ObjectAccessControl> GrpcClient::PatchDefaultObjectAcl(
921-
PatchDefaultObjectAclRequest const&) {
922-
return Status(StatusCode::kUnimplemented, __func__);
921+
PatchDefaultObjectAclRequest const& request) {
922+
auto get_request = GetBucketMetadataRequest(request.bucket_name());
923+
request.ForEachOption(CopyCommonOptions(get_request));
924+
auto updater = [&request](std::vector<ObjectAccessControl> acl) {
925+
return UpsertAcl(std::move(acl), request.entity(),
926+
GrpcObjectAccessControlParser::Role(request.patch()));
927+
};
928+
return FindDefaultObjectAccessControl(
929+
ModifyDefaultAccessControl(get_request, updater), request.entity());
923930
}
924931

925932
StatusOr<ServiceAccount> GrpcClient::GetServiceAccount(

google/cloud/storage/internal/grpc_client_test.cc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,6 +1700,59 @@ TEST_F(GrpcClientTest, UpdateDefaultObjectAclPatchFails) {
17001700
EXPECT_THAT(response, StatusIs(StatusCode::kUnavailable));
17011701
}
17021702

1703+
TEST_F(GrpcClientTest, PatchDefaultObjectAclFailure) {
1704+
auto mock = std::make_shared<testing::MockStorageStub>();
1705+
EXPECT_CALL(*mock, GetBucket)
1706+
.WillOnce([this](grpc::ClientContext& context,
1707+
v2::GetBucketRequest const& request) {
1708+
auto metadata = GetMetadata(context);
1709+
EXPECT_THAT(metadata, UnorderedElementsAre(
1710+
Pair("x-goog-quota-user", "test-quota-user"),
1711+
Pair("x-goog-fieldmask", "field1,field2")));
1712+
EXPECT_THAT(request.name(), "projects/_/buckets/test-bucket-name");
1713+
return PermanentError();
1714+
});
1715+
1716+
auto client = CreateTestClient(mock);
1717+
auto response = client->PatchDefaultObjectAcl(
1718+
PatchDefaultObjectAclRequest(
1719+
"test-bucket-name", "test-entity3",
1720+
ObjectAccessControlPatchBuilder().set_role("updated-role"))
1721+
.set_multiple_options(Fields("field1,field2"),
1722+
QuotaUser("test-quota-user"),
1723+
UserProject("test-user-project")));
1724+
EXPECT_EQ(response.status(), PermanentError());
1725+
}
1726+
1727+
TEST_F(GrpcClientTest, PatchDefaultObjectAclPatchFails) {
1728+
auto mock = std::make_shared<testing::MockStorageStub>();
1729+
EXPECT_CALL(*mock, GetBucket)
1730+
.WillOnce([&](grpc::ClientContext&, v2::GetBucketRequest const&) {
1731+
v2::Bucket response;
1732+
EXPECT_TRUE(TextFormat::ParseFromString(kBucketProtoText, &response));
1733+
return response;
1734+
});
1735+
EXPECT_CALL(*mock, UpdateBucket)
1736+
.WillOnce([](grpc::ClientContext&,
1737+
v2::UpdateBucketRequest const& request) {
1738+
EXPECT_EQ(request.bucket().name(), "projects/_/buckets/test-bucket-id");
1739+
auto expected = v2::ObjectAccessControl();
1740+
expected.set_entity("test-entity3");
1741+
expected.set_role("updated-role");
1742+
EXPECT_THAT(request.bucket().default_object_acl(),
1743+
Contains(IsProtoEqual(expected)));
1744+
EXPECT_THAT(request.update_mask().paths(),
1745+
ElementsAre("default_object_acl"));
1746+
return Status(StatusCode::kFailedPrecondition, "conflict");
1747+
});
1748+
1749+
auto client = CreateTestClient(mock);
1750+
auto response = client->PatchDefaultObjectAcl(PatchDefaultObjectAclRequest(
1751+
"test-bucket-id", "test-entity3",
1752+
ObjectAccessControlPatchBuilder().set_role("updated-role")));
1753+
EXPECT_THAT(response, StatusIs(StatusCode::kUnavailable));
1754+
}
1755+
17031756
TEST_F(GrpcClientTest, GetServiceAccount) {
17041757
auto mock = std::make_shared<testing::MockStorageStub>();
17051758
EXPECT_CALL(*mock, GetServiceAccount)

google/cloud/storage/tests/grpc_default_object_acl_integration_test.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,25 @@ TEST_F(GrpcDefaultObjectAclIntegrationTest, AclCRUD) {
120120
ObjectAccessControl::ROLE_OWNER()));
121121
ASSERT_STATUS_OK(updated_acl);
122122

123+
auto patched_acl =
124+
client->PatchDefaultObjectAcl(bucket_name, viewers,
125+
ObjectAccessControlPatchBuilder().set_role(
126+
ObjectAccessControl::ROLE_READER()));
127+
ASSERT_STATUS_OK(patched_acl);
128+
EXPECT_EQ(patched_acl->entity(), create_acl->entity());
129+
EXPECT_EQ(patched_acl->role(), ObjectAccessControl::ROLE_READER());
130+
131+
// "Patching" an entity that does not exist should create the entity
132+
delete_acl = client->DeleteDefaultObjectAcl(bucket_name, viewers);
133+
ASSERT_STATUS_OK(delete_acl);
134+
patched_acl =
135+
client->PatchDefaultObjectAcl(bucket_name, viewers,
136+
ObjectAccessControlPatchBuilder().set_role(
137+
ObjectAccessControl::ROLE_READER()));
138+
ASSERT_STATUS_OK(patched_acl);
139+
EXPECT_EQ(patched_acl->entity(), create_acl->entity());
140+
EXPECT_EQ(patched_acl->role(), ObjectAccessControl::ROLE_READER());
141+
123142
delete_acl = client->DeleteDefaultObjectAcl(bucket_name, viewers);
124143
ASSERT_STATUS_OK(delete_acl);
125144

0 commit comments

Comments
 (0)