From 49a1162e2bb9ca85545508e3a3c8823f68e84f51 Mon Sep 17 00:00:00 2001 From: Tobias Happ Date: Fri, 2 Oct 2020 14:27:15 +0200 Subject: [PATCH] fix: prevent npe caused by missing parentheses --- .../api/gax/retrying/BasicRetryingFuture.java | 7 +- .../gax/retrying/BasicRetryingFutureTest.java | 101 ++++++++++++++++++ 2 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 gax/src/test/java/com/google/api/gax/retrying/BasicRetryingFutureTest.java diff --git a/gax/src/main/java/com/google/api/gax/retrying/BasicRetryingFuture.java b/gax/src/main/java/com/google/api/gax/retrying/BasicRetryingFuture.java index 3e85937bfc..b96fd20031 100644 --- a/gax/src/main/java/com/google/api/gax/retrying/BasicRetryingFuture.java +++ b/gax/src/main/java/com/google/api/gax/retrying/BasicRetryingFuture.java @@ -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 diff --git a/gax/src/test/java/com/google/api/gax/retrying/BasicRetryingFutureTest.java b/gax/src/test/java/com/google/api/gax/retrying/BasicRetryingFutureTest.java new file mode 100644 index 0000000000..c52ba93f04 --- /dev/null +++ b/gax/src/test/java/com/google/api/gax/retrying/BasicRetryingFutureTest.java @@ -0,0 +1,101 @@ +/* + * 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.ArgumentMatchers.any; +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.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 callable = mock(Callable.class); + @SuppressWarnings("unchecked") + RetryAlgorithm 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( + any(Throwable.class), any(Integer.class), any(TimedAttemptSettings.class))) + .thenReturn(timedAttemptSettings); + Mockito.when( + retryAlgorithm.shouldRetry( + any(Throwable.class), any(Integer.class), any(TimedAttemptSettings.class))) + .thenReturn(true); + + getLoggerInstance().setLevel(Level.FINEST); + + BasicRetryingFuture future = + new BasicRetryingFuture<>(callable, retryAlgorithm, retryingContext); + + future.handleAttempt(null, null); + + Mockito.verify(tracer).attemptFailed(any(Throwable.class), any(Duration.class)); + Mockito.verifyNoMoreInteractions(tracer); + } + + private Logger getLoggerInstance() throws NoSuchFieldException, IllegalAccessException { + Field logger = BasicRetryingFuture.class.getDeclaredField("LOG"); + logger.setAccessible(true); + + return (Logger) logger.get(BasicRetryingFuture.class); + } +}