Skip to content

Commit

Permalink
feat(GCS+gRPC): implement PatchDefaultObjectAcl() (#9487)
Browse files Browse the repository at this point in the history
  • Loading branch information
coryan committed Jul 18, 2022
1 parent c674e84 commit 76a4024
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 2 deletions.
11 changes: 9 additions & 2 deletions google/cloud/storage/internal/grpc_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -918,8 +918,15 @@ StatusOr<ObjectAccessControl> GrpcClient::UpdateDefaultObjectAcl(
}

StatusOr<ObjectAccessControl> GrpcClient::PatchDefaultObjectAcl(
PatchDefaultObjectAclRequest const&) {
return Status(StatusCode::kUnimplemented, __func__);
PatchDefaultObjectAclRequest const& request) {
auto get_request = GetBucketMetadataRequest(request.bucket_name());
request.ForEachOption(CopyCommonOptions(get_request));
auto updater = [&request](std::vector<ObjectAccessControl> acl) {
return UpsertAcl(std::move(acl), request.entity(),
GrpcObjectAccessControlParser::Role(request.patch()));
};
return FindDefaultObjectAccessControl(
ModifyDefaultAccessControl(get_request, updater), request.entity());
}

StatusOr<ServiceAccount> GrpcClient::GetServiceAccount(
Expand Down
53 changes: 53 additions & 0 deletions google/cloud/storage/internal/grpc_client_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1700,6 +1700,59 @@ TEST_F(GrpcClientTest, UpdateDefaultObjectAclPatchFails) {
EXPECT_THAT(response, StatusIs(StatusCode::kUnavailable));
}

TEST_F(GrpcClientTest, PatchDefaultObjectAclFailure) {
auto mock = std::make_shared<testing::MockStorageStub>();
EXPECT_CALL(*mock, GetBucket)
.WillOnce([this](grpc::ClientContext& context,
v2::GetBucketRequest const& request) {
auto metadata = GetMetadata(context);
EXPECT_THAT(metadata, UnorderedElementsAre(
Pair("x-goog-quota-user", "test-quota-user"),
Pair("x-goog-fieldmask", "field1,field2")));
EXPECT_THAT(request.name(), "projects/_/buckets/test-bucket-name");
return PermanentError();
});

auto client = CreateTestClient(mock);
auto response = client->PatchDefaultObjectAcl(
PatchDefaultObjectAclRequest(
"test-bucket-name", "test-entity3",
ObjectAccessControlPatchBuilder().set_role("updated-role"))
.set_multiple_options(Fields("field1,field2"),
QuotaUser("test-quota-user"),
UserProject("test-user-project")));
EXPECT_EQ(response.status(), PermanentError());
}

TEST_F(GrpcClientTest, PatchDefaultObjectAclPatchFails) {
auto mock = std::make_shared<testing::MockStorageStub>();
EXPECT_CALL(*mock, GetBucket)
.WillOnce([&](grpc::ClientContext&, v2::GetBucketRequest const&) {
v2::Bucket response;
EXPECT_TRUE(TextFormat::ParseFromString(kBucketProtoText, &response));
return response;
});
EXPECT_CALL(*mock, UpdateBucket)
.WillOnce([](grpc::ClientContext&,
v2::UpdateBucketRequest const& request) {
EXPECT_EQ(request.bucket().name(), "projects/_/buckets/test-bucket-id");
auto expected = v2::ObjectAccessControl();
expected.set_entity("test-entity3");
expected.set_role("updated-role");
EXPECT_THAT(request.bucket().default_object_acl(),
Contains(IsProtoEqual(expected)));
EXPECT_THAT(request.update_mask().paths(),
ElementsAre("default_object_acl"));
return Status(StatusCode::kFailedPrecondition, "conflict");
});

auto client = CreateTestClient(mock);
auto response = client->PatchDefaultObjectAcl(PatchDefaultObjectAclRequest(
"test-bucket-id", "test-entity3",
ObjectAccessControlPatchBuilder().set_role("updated-role")));
EXPECT_THAT(response, StatusIs(StatusCode::kUnavailable));
}

TEST_F(GrpcClientTest, GetServiceAccount) {
auto mock = std::make_shared<testing::MockStorageStub>();
EXPECT_CALL(*mock, GetServiceAccount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,25 @@ TEST_F(GrpcDefaultObjectAclIntegrationTest, AclCRUD) {
ObjectAccessControl::ROLE_OWNER()));
ASSERT_STATUS_OK(updated_acl);

auto patched_acl =
client->PatchDefaultObjectAcl(bucket_name, viewers,
ObjectAccessControlPatchBuilder().set_role(
ObjectAccessControl::ROLE_READER()));
ASSERT_STATUS_OK(patched_acl);
EXPECT_EQ(patched_acl->entity(), create_acl->entity());
EXPECT_EQ(patched_acl->role(), ObjectAccessControl::ROLE_READER());

// "Patching" an entity that does not exist should create the entity
delete_acl = client->DeleteDefaultObjectAcl(bucket_name, viewers);
ASSERT_STATUS_OK(delete_acl);
patched_acl =
client->PatchDefaultObjectAcl(bucket_name, viewers,
ObjectAccessControlPatchBuilder().set_role(
ObjectAccessControl::ROLE_READER()));
ASSERT_STATUS_OK(patched_acl);
EXPECT_EQ(patched_acl->entity(), create_acl->entity());
EXPECT_EQ(patched_acl->role(), ObjectAccessControl::ROLE_READER());

delete_acl = client->DeleteDefaultObjectAcl(bucket_name, viewers);
ASSERT_STATUS_OK(delete_acl);

Expand Down

0 comments on commit 76a4024

Please sign in to comment.