Skip to content

Commit 9664e8a

Browse files
authored
fix: update BucketInfo.LifecycleRule.LifecycleCondition equals and hashCode to include match prefix and suffix (#1729)
Add new test class ITBucketLifecycleRulesTest to validate some bucket mutations related to lifecycle rules behave as expected. Update GrpcConversions to detect an empty list and preserve null value if the value from the server is empty.
1 parent 0194639 commit 9664e8a

File tree

3 files changed

+161
-6
lines changed

3 files changed

+161
-6
lines changed

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,9 @@ public boolean equals(Object o) {
725725
&& Objects.equals(daysSinceNoncurrentTime, that.daysSinceNoncurrentTime)
726726
&& Objects.equals(noncurrentTimeBefore, that.noncurrentTimeBefore)
727727
&& Objects.equals(customTimeBefore, that.customTimeBefore)
728-
&& Objects.equals(daysSinceCustomTime, that.daysSinceCustomTime);
728+
&& Objects.equals(daysSinceCustomTime, that.daysSinceCustomTime)
729+
&& Objects.equals(matchesPrefix, that.matchesPrefix)
730+
&& Objects.equals(matchesSuffix, that.matchesSuffix);
729731
}
730732

731733
@Override
@@ -739,7 +741,9 @@ public int hashCode() {
739741
daysSinceNoncurrentTime,
740742
noncurrentTimeBefore,
741743
customTimeBefore,
742-
daysSinceCustomTime);
744+
daysSinceCustomTime,
745+
matchesPrefix,
746+
matchesSuffix);
743747
}
744748

745749
/** Builder for {@code LifecycleCondition}. */

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -654,10 +654,13 @@ private BucketInfo.LifecycleRule lifecycleRuleDecode(Bucket.Lifecycle.Rule from)
654654
if (condition.hasDaysSinceCustomTime()) {
655655
conditionBuilder.setDaysSinceCustomTime(condition.getDaysSinceCustomTime());
656656
}
657-
ifNonNull(
658-
condition.getMatchesStorageClassList(),
659-
toImmutableListOf(StorageClass::valueOf),
660-
conditionBuilder::setMatchesStorageClass);
657+
if (!condition.getMatchesStorageClassList().isEmpty()) {
658+
ImmutableList<StorageClass> collect =
659+
condition.getMatchesStorageClassList().stream()
660+
.map(StorageClass::valueOf)
661+
.collect(ImmutableList.toImmutableList());
662+
conditionBuilder.setMatchesStorageClass(collect);
663+
}
661664
conditionBuilder.setMatchesPrefix(condition.getMatchesPrefixList());
662665
conditionBuilder.setMatchesSuffix(condition.getMatchesSuffixList());
663666
return new BucketInfo.LifecycleRule(lifecycleAction, conditionBuilder.build());
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright 2022 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.Bucket;
22+
import com.google.cloud.storage.BucketInfo;
23+
import com.google.cloud.storage.BucketInfo.LifecycleRule;
24+
import com.google.cloud.storage.BucketInfo.LifecycleRule.LifecycleAction;
25+
import com.google.cloud.storage.BucketInfo.LifecycleRule.LifecycleCondition;
26+
import com.google.cloud.storage.Storage;
27+
import com.google.cloud.storage.Storage.BucketTargetOption;
28+
import com.google.cloud.storage.StorageFixture;
29+
import com.google.common.collect.ImmutableList;
30+
import com.google.common.collect.ImmutableMap;
31+
import java.util.UUID;
32+
import org.junit.ClassRule;
33+
import org.junit.Rule;
34+
import org.junit.Test;
35+
import org.junit.rules.TestName;
36+
import org.junit.runner.RunWith;
37+
import org.junit.runners.Parameterized;
38+
import org.junit.runners.Parameterized.Parameters;
39+
40+
@RunWith(Parameterized.class)
41+
public final class ITBucketLifecycleRulesTest {
42+
43+
@ClassRule(order = 1)
44+
public static final StorageFixture storageFixtureHttp = StorageFixture.defaultHttp();
45+
46+
@ClassRule(order = 1)
47+
public static final StorageFixture storageFixtureGrpc = StorageFixture.defaultGrpc();
48+
49+
@Rule public final TestName testName = new TestName();
50+
51+
private final Storage storage;
52+
53+
public ITBucketLifecycleRulesTest(String ignore, StorageFixture storageFixture) {
54+
this.storage = storageFixture.getInstance();
55+
}
56+
57+
@Parameters(name = "{0}")
58+
public static Iterable<Object[]> parameters() {
59+
return ImmutableList.of(
60+
new Object[] {"JSON/Prod", storageFixtureHttp},
61+
new Object[] {"GRPC/Prod", storageFixtureGrpc});
62+
}
63+
64+
@Test
65+
public void deleteRule_addingALabelToABucketWithASingleDeleteRuleOnlyModifiesTheLabels()
66+
throws Exception {
67+
LifecycleRule d1 =
68+
new LifecycleRule(
69+
LifecycleAction.newDeleteAction(),
70+
LifecycleCondition.newBuilder()
71+
.setMatchesPrefix(ImmutableList.of("pre"))
72+
.setMatchesSuffix(ImmutableList.of("suf"))
73+
.setAge(50)
74+
.build());
75+
BucketInfo info = baseInfo().setLifecycleRules(ImmutableList.of(d1)).build();
76+
77+
try (TemporaryBucket tmp =
78+
TemporaryBucket.newBuilder()
79+
.setBucketInfo(info)
80+
.setStorage(storageFixtureHttp.getInstance())
81+
.build()) {
82+
BucketInfo bucket = tmp.getBucket();
83+
assertThat(bucket.getLabels()).isNull();
84+
85+
ImmutableMap<String, String> labels = ImmutableMap.of("label1", "val1");
86+
BucketInfo withLabels = bucket.toBuilder().setLabels(labels).build();
87+
Bucket update = storage.update(withLabels, BucketTargetOption.metagenerationMatch());
88+
assertThat(update.getLabels()).isEqualTo(labels);
89+
assertThat(update.getLifecycleRules()).isEqualTo(ImmutableList.of(d1));
90+
}
91+
}
92+
93+
@Test
94+
public void deleteRule_modifyingLifecycleRulesMatchesLastOperation() throws Exception {
95+
BucketInfo info;
96+
{
97+
LifecycleRule d1 =
98+
new LifecycleRule(
99+
LifecycleAction.newDeleteAction(),
100+
LifecycleCondition.newBuilder()
101+
.setMatchesPrefix(ImmutableList.of("pre"))
102+
.setMatchesSuffix(ImmutableList.of("suf"))
103+
.setAge(50)
104+
.build());
105+
info = baseInfo().setLifecycleRules(ImmutableList.of(d1)).build();
106+
}
107+
108+
try (TemporaryBucket tmp =
109+
TemporaryBucket.newBuilder()
110+
.setBucketInfo(info)
111+
.setStorage(storageFixtureHttp.getInstance())
112+
.build()) {
113+
BucketInfo bucket = tmp.getBucket();
114+
115+
ImmutableList<LifecycleRule> newRules =
116+
bucket.getLifecycleRules().stream()
117+
.map(
118+
r -> {
119+
if (r.getAction().equals(LifecycleAction.newDeleteAction())) {
120+
LifecycleCondition condition = r.getCondition();
121+
LifecycleCondition.Builder b = condition.toBuilder();
122+
b.setMatchesPrefix(
123+
ImmutableList.<String>builder()
124+
.addAll(condition.getMatchesPrefix())
125+
.add("a")
126+
.build());
127+
b.setMatchesSuffix(
128+
ImmutableList.<String>builder()
129+
.addAll(condition.getMatchesSuffix())
130+
.add("z")
131+
.build());
132+
return new LifecycleRule(LifecycleAction.newDeleteAction(), b.build());
133+
} else {
134+
return r;
135+
}
136+
})
137+
.collect(ImmutableList.toImmutableList());
138+
139+
BucketInfo modifiedRules = bucket.toBuilder().setLifecycleRules(newRules).build();
140+
Bucket update = storage.update(modifiedRules, BucketTargetOption.metagenerationMatch());
141+
assertThat(update.getLifecycleRules()).isEqualTo(newRules);
142+
}
143+
}
144+
145+
private static BucketInfo.Builder baseInfo() {
146+
return BucketInfo.newBuilder(String.format("java-storage-grpc-%s", UUID.randomUUID()));
147+
}
148+
}

0 commit comments

Comments
 (0)