Skip to content
This repository was archived by the owner on Sep 26, 2023. It is now read-only.

Commit b856351

Browse files
Gerschtlielharo
andauthored
fix: prevent npe caused by missing parentheses (#1198)
Co-authored-by: Elliotte Rusty Harold <[email protected]>
1 parent 88328eb commit b856351

File tree

2 files changed

+110
-3
lines changed

2 files changed

+110
-3
lines changed

gax/src/main/java/com/google/api/gax/retrying/BasicRetryingFuture.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,10 @@ void handleAttempt(Throwable throwable, ResponseT response) {
176176
Level.FINEST,
177177
"Retrying with:\n{0}\n{1}\n{2}\n{3}",
178178
new Object[] {
179-
"enclosingMethod: " + callable.getClass().getEnclosingMethod() != null
180-
? callable.getClass().getEnclosingMethod().getName()
181-
: "",
179+
"enclosingMethod: "
180+
+ (callable.getClass().getEnclosingMethod() != null
181+
? callable.getClass().getEnclosingMethod().getName()
182+
: ""),
182183
"attemptCount: " + attemptSettings.getAttemptCount(),
183184
"delay: " + attemptSettings.getRetryDelay(),
184185
"retriableException: " + throwable
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright 2020 Google LLC
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are
6+
* met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* * Redistributions in binary form must reproduce the above
11+
* copyright notice, this list of conditions and the following disclaimer
12+
* in the documentation and/or other materials provided with the
13+
* distribution.
14+
* * Neither the name of Google LLC nor the names of its
15+
* contributors may be used to endorse or promote products derived from
16+
* this software without specific prior written permission.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
package com.google.api.gax.retrying;
31+
32+
import static org.mockito.Mockito.mock;
33+
34+
import com.google.api.gax.tracing.ApiTracer;
35+
import java.lang.reflect.Field;
36+
import java.util.concurrent.Callable;
37+
import java.util.logging.Level;
38+
import java.util.logging.Logger;
39+
import org.junit.After;
40+
import org.junit.Before;
41+
import org.junit.Test;
42+
import org.junit.runner.RunWith;
43+
import org.junit.runners.JUnit4;
44+
import org.mockito.ArgumentMatchers;
45+
import org.mockito.Mockito;
46+
import org.threeten.bp.Duration;
47+
48+
@RunWith(JUnit4.class)
49+
public class BasicRetryingFutureTest {
50+
private Level logLevel;
51+
52+
@Before
53+
public void setUp() throws Exception {
54+
logLevel = getLoggerInstance().getLevel();
55+
}
56+
57+
@After
58+
public void tearDown() throws Exception {
59+
getLoggerInstance().setLevel(logLevel);
60+
}
61+
62+
@Test
63+
public void testHandleAttemptDoesNotThrowNPEWhenLogLevelLowerThanFiner() throws Exception {
64+
@SuppressWarnings("unchecked")
65+
Callable<Integer> callable = mock(Callable.class);
66+
@SuppressWarnings("unchecked")
67+
RetryAlgorithm<Integer> retryAlgorithm = mock(RetryAlgorithm.class);
68+
RetryingContext retryingContext = mock(RetryingContext.class);
69+
ApiTracer tracer = mock(ApiTracer.class);
70+
TimedAttemptSettings timedAttemptSettings = mock(TimedAttemptSettings.class);
71+
72+
Mockito.when(retryingContext.getTracer()).thenReturn(tracer);
73+
74+
Mockito.when(retryAlgorithm.createFirstAttempt()).thenReturn(timedAttemptSettings);
75+
Mockito.when(
76+
retryAlgorithm.createNextAttempt(
77+
ArgumentMatchers.<Throwable>any(),
78+
ArgumentMatchers.<Integer>any(),
79+
ArgumentMatchers.<TimedAttemptSettings>any()))
80+
.thenReturn(timedAttemptSettings);
81+
Mockito.when(
82+
retryAlgorithm.shouldRetry(
83+
ArgumentMatchers.<Throwable>any(),
84+
ArgumentMatchers.<Integer>any(),
85+
ArgumentMatchers.<TimedAttemptSettings>any()))
86+
.thenReturn(true);
87+
88+
getLoggerInstance().setLevel(Level.FINEST);
89+
90+
BasicRetryingFuture<Integer> future =
91+
new BasicRetryingFuture<>(callable, retryAlgorithm, retryingContext);
92+
93+
future.handleAttempt(null, null);
94+
95+
Mockito.verify(tracer)
96+
.attemptFailed(ArgumentMatchers.<Throwable>any(), ArgumentMatchers.<Duration>any());
97+
Mockito.verifyNoMoreInteractions(tracer);
98+
}
99+
100+
private Logger getLoggerInstance() throws NoSuchFieldException, IllegalAccessException {
101+
Field logger = BasicRetryingFuture.class.getDeclaredField("LOG");
102+
logger.setAccessible(true);
103+
104+
return (Logger) logger.get(BasicRetryingFuture.class);
105+
}
106+
}

0 commit comments

Comments
 (0)