Skip to content
Permalink
Browse files
fix: prevent npe caused by missing parentheses (#1198)
Co-authored-by: Elliotte Rusty Harold <elharo@users.noreply.github.com>
  • Loading branch information
Gerschtli and elharo committed Oct 12, 2020
1 parent 88328eb commit b85635123f987f9808086f14a58dd8c7418a3bd8
@@ -176,9 +176,10 @@ void handleAttempt(Throwable throwable, ResponseT response) {
Level.FINEST,
"Retrying with:\n{0}\n{1}\n{2}\n{3}",
new Object[] {
"enclosingMethod: " + callable.getClass().getEnclosingMethod() != null
? callable.getClass().getEnclosingMethod().getName()
: "",
"enclosingMethod: "
+ (callable.getClass().getEnclosingMethod() != null
? callable.getClass().getEnclosingMethod().getName()
: ""),
"attemptCount: " + attemptSettings.getAttemptCount(),
"delay: " + attemptSettings.getRetryDelay(),
"retriableException: " + throwable
@@ -0,0 +1,106 @@
/*
* Copyright 2020 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.api.gax.retrying;

import static org.mockito.Mockito.mock;

import com.google.api.gax.tracing.ApiTracer;
import java.lang.reflect.Field;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.threeten.bp.Duration;

@RunWith(JUnit4.class)
public class BasicRetryingFutureTest {
private Level logLevel;

@Before
public void setUp() throws Exception {
logLevel = getLoggerInstance().getLevel();
}

@After
public void tearDown() throws Exception {
getLoggerInstance().setLevel(logLevel);
}

@Test
public void testHandleAttemptDoesNotThrowNPEWhenLogLevelLowerThanFiner() throws Exception {
@SuppressWarnings("unchecked")
Callable<Integer> callable = mock(Callable.class);
@SuppressWarnings("unchecked")
RetryAlgorithm<Integer> retryAlgorithm = mock(RetryAlgorithm.class);
RetryingContext retryingContext = mock(RetryingContext.class);
ApiTracer tracer = mock(ApiTracer.class);
TimedAttemptSettings timedAttemptSettings = mock(TimedAttemptSettings.class);

Mockito.when(retryingContext.getTracer()).thenReturn(tracer);

Mockito.when(retryAlgorithm.createFirstAttempt()).thenReturn(timedAttemptSettings);
Mockito.when(
retryAlgorithm.createNextAttempt(
ArgumentMatchers.<Throwable>any(),
ArgumentMatchers.<Integer>any(),
ArgumentMatchers.<TimedAttemptSettings>any()))
.thenReturn(timedAttemptSettings);
Mockito.when(
retryAlgorithm.shouldRetry(
ArgumentMatchers.<Throwable>any(),
ArgumentMatchers.<Integer>any(),
ArgumentMatchers.<TimedAttemptSettings>any()))
.thenReturn(true);

getLoggerInstance().setLevel(Level.FINEST);

BasicRetryingFuture<Integer> future =
new BasicRetryingFuture<>(callable, retryAlgorithm, retryingContext);

future.handleAttempt(null, null);

Mockito.verify(tracer)
.attemptFailed(ArgumentMatchers.<Throwable>any(), ArgumentMatchers.<Duration>any());
Mockito.verifyNoMoreInteractions(tracer);
}

private Logger getLoggerInstance() throws NoSuchFieldException, IllegalAccessException {
Field logger = BasicRetryingFuture.class.getDeclaredField("LOG");
logger.setAccessible(true);

return (Logger) logger.get(BasicRetryingFuture.class);
}
}

0 comments on commit b856351

Please sign in to comment.