Skip to content

Commit c2a8d0c

Browse files
authored
test: update ITDatastoreTest test to attempt multiple times if a test fails (#104)
Datastore (when not Firestore in Datastore mode) is eventually consistent. Sometimes this means queries may not show the expected results within the short timespan of a test. This change adds a new JUnit Rule - MultipleAttemptsRule - which allows tests to attempt to succeed up to three times. If a test is unable to pass within the 3 allowed attempts, the errors from each attempt will be returned as an overall failure. Fixes #97 Fixes #101
1 parent ad6b880 commit c2a8d0c

3 files changed

Lines changed: 110 additions & 0 deletions

File tree

google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITDatastoreTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ public class ITDatastoreTest {
154154

155155
@Rule public Timeout globalTimeout = Timeout.seconds(100);
156156

157+
@Rule public MultipleAttemptsRule multipleAttemptsRule = new MultipleAttemptsRule(3);
158+
157159
@AfterClass
158160
public static void afterClass() {
159161
HELPER.deleteNamespace();
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2020 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.datastore.it;
18+
19+
import static com.google.common.base.Preconditions.checkState;
20+
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
import org.junit.rules.TestRule;
24+
import org.junit.runner.Description;
25+
import org.junit.runners.model.MultipleFailureException;
26+
import org.junit.runners.model.Statement;
27+
28+
/**
29+
* A JUnit rule that allows us to allow multiple attempts of a test execution before it is
30+
* ultimately failed. When it fails, all failures will be propagated as the result of the test.
31+
*/
32+
public final class MultipleAttemptsRule implements TestRule {
33+
private final long initialBackoffMillis;
34+
private final int attemptCount;
35+
36+
MultipleAttemptsRule(int attemptCount) {
37+
this(attemptCount, 1000L);
38+
}
39+
40+
MultipleAttemptsRule(int attemptCount, long initialBackoffMillis) {
41+
checkState(attemptCount > 0, "attemptCount must be > 0");
42+
checkState(initialBackoffMillis > 0, "initialBackoffMillis must be > 0");
43+
this.initialBackoffMillis = initialBackoffMillis;
44+
this.attemptCount = attemptCount;
45+
}
46+
47+
@Override
48+
public Statement apply(final Statement base, Description description) {
49+
return new Statement() {
50+
@Override
51+
public void evaluate() throws Throwable {
52+
List<Throwable> failures = new ArrayList<>();
53+
54+
long retryIntervalMillis = initialBackoffMillis;
55+
56+
for (int i = 1; i <= attemptCount; i++) {
57+
try {
58+
base.evaluate();
59+
return;
60+
} catch (Throwable t) {
61+
failures.add(t);
62+
Thread.sleep(retryIntervalMillis);
63+
retryIntervalMillis *= 1.5f;
64+
}
65+
}
66+
67+
MultipleFailureException.assertEmpty(failures);
68+
}
69+
};
70+
}
71+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2020 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.datastore.it;
18+
19+
import static org.junit.Assert.assertEquals;
20+
21+
import org.junit.Rule;
22+
import org.junit.Test;
23+
24+
public final class MultipleAttemptsRuleTest {
25+
26+
private static final int NUMBER_OF_ATTEMPTS = 5;
27+
28+
@Rule public MultipleAttemptsRule rr = new MultipleAttemptsRule(NUMBER_OF_ATTEMPTS, 10);
29+
30+
private int numberAttempted = 0;
31+
32+
@Test
33+
public void wontPassUntil5() {
34+
numberAttempted += 1;
35+
assertEquals(NUMBER_OF_ATTEMPTS, numberAttempted);
36+
}
37+
}

0 commit comments

Comments
 (0)