Skip to content

Commit 330e795

Browse files
authored
fix: update grpc default metadata projection to include acl same as json (#2150)
1 parent f00f843 commit 330e795

File tree

3 files changed

+176
-5
lines changed

3 files changed

+176
-5
lines changed

google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcStorageImpl.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ final class GrpcStorageImpl extends BaseService<StorageOptions>
164164
StandardOpenOption.TRUNCATE_EXISTING);
165165
private static final BucketSourceOption[] EMPTY_BUCKET_SOURCE_OPTIONS = new BucketSourceOption[0];
166166

167+
private static final Opts<Fields> ALL_BLOB_FIELDS =
168+
Opts.from(UnifiedOpts.fields(ImmutableSet.copyOf(BlobField.values())));
169+
private static final Opts<Fields> ALL_BUCKET_FIELDS =
170+
Opts.from(UnifiedOpts.fields(ImmutableSet.copyOf(BucketField.values())));
171+
167172
final StorageClient storageClient;
168173
final WriterFactory writerFactory;
169174
final GrpcConversions codecs;
@@ -420,7 +425,7 @@ public Blob get(BlobId blob) {
420425

421426
@Override
422427
public Page<Bucket> list(BucketListOption... options) {
423-
Opts<BucketListOpt> opts = Opts.unwrap(options).prepend(defaultOpts);
428+
Opts<BucketListOpt> opts = Opts.unwrap(options).prepend(defaultOpts).prepend(ALL_BUCKET_FIELDS);
424429
GrpcCallContext grpcCallContext =
425430
opts.grpcMetadataMapper().apply(GrpcCallContext.createDefault());
426431
ListBucketsRequest request =
@@ -448,7 +453,7 @@ public Page<Bucket> list(BucketListOption... options) {
448453

449454
@Override
450455
public Page<Blob> list(String bucket, BlobListOption... options) {
451-
Opts<ObjectListOpt> opts = Opts.unwrap(options).prepend(defaultOpts);
456+
Opts<ObjectListOpt> opts = Opts.unwrap(options).prepend(defaultOpts).prepend(ALL_BLOB_FIELDS);
452457
GrpcCallContext grpcCallContext =
453458
opts.grpcMetadataMapper().apply(GrpcCallContext.createDefault());
454459
ListObjectsRequest.Builder builder =
@@ -1958,7 +1963,8 @@ private Object updateObject(UpdateObjectRequest req) {
19581963

19591964
@Nullable
19601965
private Blob internalBlobGet(BlobId blob, Opts<ObjectSourceOpt> unwrap) {
1961-
Opts<ObjectSourceOpt> opts = unwrap.resolveFrom(blob).prepend(defaultOpts);
1966+
Opts<ObjectSourceOpt> opts =
1967+
unwrap.resolveFrom(blob).prepend(defaultOpts).prepend(ALL_BLOB_FIELDS);
19621968
GrpcCallContext grpcCallContext =
19631969
opts.grpcMetadataMapper().apply(GrpcCallContext.createDefault());
19641970
GetObjectRequest.Builder builder =
@@ -1983,7 +1989,7 @@ private Blob internalBlobGet(BlobId blob, Opts<ObjectSourceOpt> unwrap) {
19831989

19841990
@Nullable
19851991
private Bucket internalBucketGet(String bucket, Opts<BucketSourceOpt> unwrap) {
1986-
Opts<BucketSourceOpt> opts = unwrap.prepend(defaultOpts);
1992+
Opts<BucketSourceOpt> opts = unwrap.prepend(defaultOpts).prepend(ALL_BUCKET_FIELDS);
19871993
GrpcCallContext grpcCallContext =
19881994
opts.grpcMetadataMapper().apply(GrpcCallContext.createDefault());
19891995
GetBucketRequest.Builder builder =

google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITBlobWriteChannelTest.java

-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ public void testWriteChannelExistingBlob() throws IOException {
145145
@Test
146146
public void changeChunkSizeAfterWrite() throws IOException {
147147
BlobInfo info = BlobInfo.newBuilder(bucket, generator.randomObjectName()).build();
148-
System.out.println("info = " + info);
149148

150149
int _512KiB = 512 * 1024;
151150
byte[] bytes = DataGenerator.base64Characters().genBytes(_512KiB + 13);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright 2023 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.storage.it;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
21+
import com.google.cloud.storage.Acl;
22+
import com.google.cloud.storage.Acl.Entity;
23+
import com.google.cloud.storage.Blob;
24+
import com.google.cloud.storage.Bucket;
25+
import com.google.cloud.storage.BucketInfo;
26+
import com.google.cloud.storage.Storage;
27+
import com.google.cloud.storage.Storage.BlobListOption;
28+
import com.google.cloud.storage.Storage.BucketListOption;
29+
import com.google.cloud.storage.TransportCompatibility.Transport;
30+
import com.google.cloud.storage.it.runner.StorageITRunner;
31+
import com.google.cloud.storage.it.runner.annotations.Backend;
32+
import com.google.cloud.storage.it.runner.annotations.Inject;
33+
import com.google.cloud.storage.it.runner.annotations.SingleBackend;
34+
import com.google.cloud.storage.it.runner.annotations.StorageFixture;
35+
import com.google.cloud.storage.it.runner.registry.ObjectsFixture;
36+
import com.google.common.base.MoreObjects;
37+
import java.util.List;
38+
import java.util.Objects;
39+
import java.util.stream.Collectors;
40+
import org.checkerframework.checker.nullness.qual.NonNull;
41+
import org.checkerframework.checker.nullness.qual.Nullable;
42+
import org.junit.Test;
43+
import org.junit.runner.RunWith;
44+
45+
@RunWith(StorageITRunner.class)
46+
@SingleBackend(Backend.PROD)
47+
public final class ITDefaultProjectionCompatibilityTest {
48+
49+
@Inject
50+
@StorageFixture(Transport.HTTP)
51+
public Storage http;
52+
53+
@Inject
54+
@StorageFixture(Transport.GRPC)
55+
public Storage grpc;
56+
57+
@Inject public BucketInfo bucket;
58+
59+
@Inject public ObjectsFixture objectsFixture;
60+
61+
@Test
62+
public void objectMetadata_includesAcls() {
63+
Blob httpBlob = http.get(objectsFixture.getInfo1().getBlobId());
64+
Blob grpcBlob = grpc.get(objectsFixture.getInfo1().getBlobId());
65+
66+
assertThat(extractFromBlob(grpcBlob)).isEqualTo(extractFromBlob(httpBlob));
67+
}
68+
69+
@Test
70+
public void listObjectMetadata_includesAcls() {
71+
String bucketName = bucket.getName();
72+
BlobListOption prefix = BlobListOption.prefix(objectsFixture.getInfo1().getBlobId().getName());
73+
List<Blob> httpBlob = http.list(bucketName, prefix).streamAll().collect(Collectors.toList());
74+
List<Blob> grpcBlob = grpc.list(bucketName, prefix).streamAll().collect(Collectors.toList());
75+
76+
List<AclRelatedFields> a = extractFromBlobs(httpBlob);
77+
List<AclRelatedFields> b = extractFromBlobs(grpcBlob);
78+
79+
assertThat(a).isEqualTo(b);
80+
}
81+
82+
@Test
83+
public void bucketMetadata_includesAcls() {
84+
Bucket httpBucket = http.get(bucket.getName());
85+
Bucket grpcBucket = grpc.get(bucket.getName());
86+
87+
assertThat(extractFromBucket(httpBucket)).isEqualTo(extractFromBucket(grpcBucket));
88+
}
89+
90+
@Test
91+
public void listBucketMetadata_includesAcls() {
92+
BucketListOption prefix = BucketListOption.prefix(bucket.getName());
93+
List<Bucket> httpBucket = http.list(prefix).streamAll().collect(Collectors.toList());
94+
List<Bucket> grpcBucket = grpc.list(prefix).streamAll().collect(Collectors.toList());
95+
96+
List<AclRelatedFields> a = extractFromBuckets(httpBucket);
97+
List<AclRelatedFields> b = extractFromBuckets(grpcBucket);
98+
99+
assertThat(a).isEqualTo(b);
100+
}
101+
102+
@NonNull
103+
private static List<AclRelatedFields> extractFromBlobs(List<Blob> httpBlob) {
104+
return httpBlob.stream()
105+
.map(ITDefaultProjectionCompatibilityTest::extractFromBlob)
106+
.collect(Collectors.toList());
107+
}
108+
109+
@NonNull
110+
private static AclRelatedFields extractFromBlob(Blob b) {
111+
return new AclRelatedFields(b.getOwner(), b.getAcl(), null);
112+
}
113+
114+
@NonNull
115+
private static List<AclRelatedFields> extractFromBuckets(List<Bucket> httpBucket) {
116+
return httpBucket.stream()
117+
.map(ITDefaultProjectionCompatibilityTest::extractFromBucket)
118+
.collect(Collectors.toList());
119+
}
120+
121+
@NonNull
122+
private static AclRelatedFields extractFromBucket(Bucket b) {
123+
return new AclRelatedFields(b.getOwner(), b.getAcl(), null);
124+
}
125+
126+
private static final class AclRelatedFields {
127+
@Nullable private final Entity owner;
128+
@Nullable private final List<Acl> acls;
129+
@Nullable private final List<Acl> defaultAcls;
130+
131+
private AclRelatedFields(
132+
@Nullable Entity owner, @Nullable List<Acl> acls, @Nullable List<Acl> defaultAcls) {
133+
this.owner = owner;
134+
this.acls = acls;
135+
this.defaultAcls = defaultAcls;
136+
}
137+
138+
@Override
139+
public boolean equals(Object o) {
140+
if (this == o) {
141+
return true;
142+
}
143+
if (!(o instanceof AclRelatedFields)) {
144+
return false;
145+
}
146+
AclRelatedFields that = (AclRelatedFields) o;
147+
return Objects.equals(owner, that.owner)
148+
&& Objects.equals(acls, that.acls)
149+
&& Objects.equals(defaultAcls, that.defaultAcls);
150+
}
151+
152+
@Override
153+
public int hashCode() {
154+
return Objects.hash(owner, acls, defaultAcls);
155+
}
156+
157+
@Override
158+
public String toString() {
159+
return MoreObjects.toStringHelper(this)
160+
.add("owner", owner)
161+
.add("acls", acls)
162+
.add("defaultAcls", defaultAcls)
163+
.toString();
164+
}
165+
}
166+
}

0 commit comments

Comments
 (0)