|
26 | 26 | import com.google.common.util.concurrent.Futures; |
27 | 27 | import com.google.common.util.concurrent.ListenableFuture; |
28 | 28 | import com.google.common.util.concurrent.MoreExecutors; |
| 29 | +import com.google.errorprone.annotations.CanIgnoreReturnValue; |
29 | 30 | import com.google.protobuf.Empty; |
30 | 31 | import io.grpc.CallOptions; |
31 | 32 | import io.grpc.ManagedChannel; |
|
45 | 46 | import java.util.HashMap; |
46 | 47 | import java.util.List; |
47 | 48 | import java.util.Map; |
| 49 | +import java.util.concurrent.atomic.AtomicReference; |
| 50 | + |
48 | 51 | import javax.annotation.Nullable; |
49 | 52 | import org.junit.After; |
50 | 53 | import org.junit.Before; |
@@ -76,6 +79,7 @@ public void setupServiceDefinitionsAndMethods() { |
76 | 79 | MethodDescriptor.newBuilder(marshaller, marshaller) |
77 | 80 | .setFullMethodName(name) |
78 | 81 | .setType(MethodDescriptor.MethodType.UNARY) |
| 82 | + .setSampledToLocalTracing(true) |
79 | 83 | .build(); |
80 | 84 | ServerCallHandler<Empty, Empty> callHandler = |
81 | 85 | ServerCalls.asyncUnaryCall( |
@@ -139,12 +143,16 @@ private void assertCallSuccess(MethodDescriptor<Empty, Empty> method) { |
139 | 143 | .isNotNull(); |
140 | 144 | } |
141 | 145 |
|
142 | | - private void assertCallFailure(MethodDescriptor<Empty, Empty> method, Status status) { |
| 146 | + @CanIgnoreReturnValue |
| 147 | + private StatusRuntimeException assertCallFailure( |
| 148 | + MethodDescriptor<Empty, Empty> method, Status status) { |
143 | 149 | try { |
144 | 150 | ClientCalls.blockingUnaryCall(channel, method, CallOptions.DEFAULT, null); |
145 | | - fail(); |
| 151 | + fail("Expected call to " + method.getFullMethodName() + " to fail but it succeeded."); |
| 152 | + throw new AssertionError(); // impossible |
146 | 153 | } catch (StatusRuntimeException sre) { |
147 | 154 | assertThat(sre.getStatus().getCode()).isEqualTo(status.getCode()); |
| 155 | + return sre; |
148 | 156 | } |
149 | 157 | } |
150 | 158 |
|
@@ -172,6 +180,70 @@ public void testServerDisallowsCalls() throws Exception { |
172 | 180 | } |
173 | 181 | } |
174 | 182 |
|
| 183 | + @Test |
| 184 | + public void testFailedFuturesPropagateOriginalException() throws Exception { |
| 185 | + String errorMessage = "something went wrong"; |
| 186 | + IllegalStateException originalException = new IllegalStateException(errorMessage); |
| 187 | + createChannel( |
| 188 | + ServerSecurityPolicy.newBuilder() |
| 189 | + .servicePolicy("foo", new AsyncSecurityPolicy() { |
| 190 | + @Override |
| 191 | + ListenableFuture<Status> checkAuthorizationAsync(int uid) { |
| 192 | + return Futures.immediateFailedFuture(originalException); |
| 193 | + } |
| 194 | + }) |
| 195 | + .build(), |
| 196 | + SecurityPolicies.internalOnly()); |
| 197 | + MethodDescriptor<Empty, Empty> method = methods.get("foo/method0"); |
| 198 | + |
| 199 | + StatusRuntimeException sre = assertCallFailure(method, Status.INTERNAL); |
| 200 | + assertThat(sre.getStatus().getDescription()).contains(errorMessage); |
| 201 | + } |
| 202 | + |
| 203 | + @Test |
| 204 | + public void testFailedFuturesAreNotCachedPermanently() throws Exception { |
| 205 | + AtomicReference<Boolean> firstAttempt = new AtomicReference<>(true); |
| 206 | + createChannel( |
| 207 | + ServerSecurityPolicy.newBuilder() |
| 208 | + .servicePolicy("foo", new AsyncSecurityPolicy() { |
| 209 | + @Override |
| 210 | + ListenableFuture<Status> checkAuthorizationAsync(int uid) { |
| 211 | + if (firstAttempt.getAndSet(false)) { |
| 212 | + return Futures.immediateFailedFuture(new IllegalStateException()); |
| 213 | + } |
| 214 | + return Futures.immediateFuture(Status.OK); |
| 215 | + } |
| 216 | + }) |
| 217 | + .build(), |
| 218 | + SecurityPolicies.internalOnly()); |
| 219 | + MethodDescriptor<Empty, Empty> method = methods.get("foo/method0"); |
| 220 | + |
| 221 | + assertCallFailure(method, Status.INTERNAL); |
| 222 | + assertCallSuccess(method); |
| 223 | + } |
| 224 | + |
| 225 | + @Test |
| 226 | + public void testCancelledFuturesAreNotCachedPermanently() throws Exception { |
| 227 | + AtomicReference<Boolean> firstAttempt = new AtomicReference<>(true); |
| 228 | + createChannel( |
| 229 | + ServerSecurityPolicy.newBuilder() |
| 230 | + .servicePolicy("foo", new AsyncSecurityPolicy() { |
| 231 | + @Override |
| 232 | + ListenableFuture<Status> checkAuthorizationAsync(int uid) { |
| 233 | + if (firstAttempt.getAndSet(false)) { |
| 234 | + return Futures.immediateCancelledFuture(); |
| 235 | + } |
| 236 | + return Futures.immediateFuture(Status.OK); |
| 237 | + } |
| 238 | + }) |
| 239 | + .build(), |
| 240 | + SecurityPolicies.internalOnly()); |
| 241 | + MethodDescriptor<Empty, Empty> method = methods.get("foo/method0"); |
| 242 | + |
| 243 | + assertCallFailure(method, Status.INTERNAL); |
| 244 | + assertCallSuccess(method); |
| 245 | + } |
| 246 | + |
175 | 247 | @Test |
176 | 248 | public void testClientDoesntTrustServer() throws Exception { |
177 | 249 | createChannel(SecurityPolicies.serverInternalOnly(), policy((uid) -> false)); |
|
0 commit comments