17
17
package io .grpc .binder .internal ;
18
18
19
19
import static com .google .common .truth .Truth .assertThat ;
20
+ import static java .util .concurrent .TimeUnit .SECONDS ;
20
21
21
22
import android .content .Context ;
22
23
import android .os .DeadObjectException ;
23
24
import android .os .Parcel ;
24
25
import android .os .RemoteException ;
25
26
import androidx .test .core .app .ApplicationProvider ;
26
27
import androidx .test .ext .junit .runners .AndroidJUnit4 ;
27
- import com .google .common .util .concurrent .Futures ;
28
- import com .google .common .util .concurrent .ListenableFuture ;
29
28
import com .google .common .util .concurrent .SettableFuture ;
29
+ import com .google .errorprone .annotations .CanIgnoreReturnValue ;
30
30
import com .google .errorprone .annotations .concurrent .GuardedBy ;
31
31
import com .google .protobuf .Empty ;
32
32
import io .grpc .CallOptions ;
38
38
import io .grpc .Status ;
39
39
import io .grpc .Status .Code ;
40
40
import io .grpc .binder .AndroidComponentAddress ;
41
- import io .grpc .binder .AsyncSecurityPolicy ;
42
41
import io .grpc .binder .BinderServerBuilder ;
43
42
import io .grpc .binder .HostServices ;
44
43
import io .grpc .binder .SecurityPolicy ;
45
44
import io .grpc .binder .internal .OneWayBinderProxies .BlackHoleOneWayBinderProxy ;
46
45
import io .grpc .binder .internal .OneWayBinderProxies .BlockingBinderDecorator ;
47
46
import io .grpc .binder .internal .OneWayBinderProxies .ThrowingOneWayBinderProxy ;
47
+ import io .grpc .binder .internal .SettableAsyncSecurityPolicy .AuthRequest ;
48
48
import io .grpc .internal .ClientStream ;
49
49
import io .grpc .internal .ClientStreamListener ;
50
50
import io .grpc .internal .ClientTransportFactory .ClientTransportOptions ;
63
63
import java .util .concurrent .Executors ;
64
64
import java .util .concurrent .LinkedBlockingQueue ;
65
65
import java .util .concurrent .ScheduledExecutorService ;
66
- import java .util .concurrent .TimeUnit ;
67
66
import javax .annotation .Nullable ;
68
67
import org .junit .After ;
69
68
import org .junit .Before ;
@@ -154,17 +153,20 @@ private class BinderClientTransportBuilder {
154
153
.setScheduledExecutorPool (executorServicePool )
155
154
.setOffloadExecutorPool (offloadServicePool );
156
155
156
+ @ CanIgnoreReturnValue
157
157
public BinderClientTransportBuilder setSecurityPolicy (SecurityPolicy securityPolicy ) {
158
158
factoryBuilder .setSecurityPolicy (securityPolicy );
159
159
return this ;
160
160
}
161
161
162
+ @ CanIgnoreReturnValue
162
163
public BinderClientTransportBuilder setBinderDecorator (
163
164
OneWayBinderProxy .Decorator binderDecorator ) {
164
165
factoryBuilder .setBinderDecorator (binderDecorator );
165
166
return this ;
166
167
}
167
168
169
+ @ CanIgnoreReturnValue
168
170
public BinderClientTransportBuilder setReadyTimeoutMillis (int timeoutMillis ) {
169
171
factoryBuilder .setReadyTimeoutMillis (timeoutMillis );
170
172
return this ;
@@ -189,7 +191,7 @@ public void tearDown() throws Exception {
189
191
private static void shutdownAndTerminate (ExecutorService executorService )
190
192
throws InterruptedException {
191
193
executorService .shutdownNow ();
192
- if (!executorService .awaitTermination (TIMEOUT_SECONDS , TimeUnit . SECONDS )) {
194
+ if (!executorService .awaitTermination (TIMEOUT_SECONDS , SECONDS )) {
193
195
throw new AssertionError ("executor failed to terminate promptly" );
194
196
}
195
197
}
@@ -371,26 +373,32 @@ public void testBlackHoleEndpointConnectTimeout() throws Exception {
371
373
372
374
@ Test
373
375
public void testBlackHoleSecurityPolicyConnectTimeout () throws Exception {
376
+ SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy ();
374
377
transport =
375
378
new BinderClientTransportBuilder ()
376
- .setSecurityPolicy (blockingSecurityPolicy )
379
+ .setSecurityPolicy (securityPolicy )
377
380
.setReadyTimeoutMillis (1_234 )
378
381
.build ();
379
382
transport .start (transportListener ).run ();
383
+ // Take the next authRequest but don't respond to it, in order to trigger the ready timeout.
384
+ AuthRequest authRequest = securityPolicy .takeNextAuthRequest (TIMEOUT_SECONDS , SECONDS );
385
+
380
386
Status transportStatus = transportListener .awaitShutdown ();
381
387
assertThat (transportStatus .getCode ()).isEqualTo (Code .DEADLINE_EXCEEDED );
382
388
assertThat (transportStatus .getDescription ()).contains ("1234" );
383
389
transportListener .awaitTermination ();
384
- blockingSecurityPolicy .provideNextCheckAuthorizationResult (Status .OK );
390
+
391
+ // If the transport gave up waiting on auth, it should cancel its request.
392
+ assertThat (authRequest .isCancelled ()).isTrue ();
385
393
}
386
394
387
395
@ Test
388
396
public void testAsyncSecurityPolicyFailure () throws Exception {
389
397
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy ();
390
398
transport = new BinderClientTransportBuilder ().setSecurityPolicy (securityPolicy ).build ();
391
399
RuntimeException exception = new NullPointerException ();
392
- securityPolicy .setAuthorizationException (exception );
393
400
transport .start (transportListener ).run ();
401
+ securityPolicy .takeNextAuthRequest (TIMEOUT_SECONDS , SECONDS ).setResult (exception );
394
402
Status transportStatus = transportListener .awaitShutdown ();
395
403
assertThat (transportStatus .getCode ()).isEqualTo (Code .INTERNAL );
396
404
assertThat (transportStatus .getCause ()).isEqualTo (exception );
@@ -401,13 +409,27 @@ public void testAsyncSecurityPolicyFailure() throws Exception {
401
409
public void testAsyncSecurityPolicySuccess () throws Exception {
402
410
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy ();
403
411
transport = new BinderClientTransportBuilder ().setSecurityPolicy (securityPolicy ).build ();
404
- securityPolicy .setAuthorizationResult (Status .PERMISSION_DENIED );
405
412
transport .start (transportListener ).run ();
413
+ securityPolicy
414
+ .takeNextAuthRequest (TIMEOUT_SECONDS , SECONDS )
415
+ .setResult (Status .PERMISSION_DENIED );
406
416
Status transportStatus = transportListener .awaitShutdown ();
407
417
assertThat (transportStatus .getCode ()).isEqualTo (Code .PERMISSION_DENIED );
408
418
transportListener .awaitTermination ();
409
419
}
410
420
421
+ @ Test
422
+ public void testAsyncSecurityPolicyCancelledUponExternalTermination () throws Exception {
423
+ SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy ();
424
+ transport = new BinderClientTransportBuilder ().setSecurityPolicy (securityPolicy ).build ();
425
+ transport .start (transportListener ).run ();
426
+ AuthRequest authRequest = securityPolicy .takeNextAuthRequest (TIMEOUT_SECONDS , SECONDS );
427
+ transport .shutdownNow (Status .UNAVAILABLE ); // 'authRequest' remains unanswered!
428
+ transportListener .awaitShutdown ();
429
+ transportListener .awaitTermination ();
430
+ assertThat (authRequest .isCancelled ()).isTrue ();
431
+ }
432
+
411
433
private static void startAndAwaitReady (
412
434
BinderTransport .BinderClientTransport transport , TestTransportListener transportListener )
413
435
throws Exception {
@@ -429,7 +451,7 @@ public void transportShutdown(Status shutdownStatus) {
429
451
}
430
452
431
453
public Status awaitShutdown () throws Exception {
432
- return shutdownStatus .get (TIMEOUT_SECONDS , TimeUnit . SECONDS );
454
+ return shutdownStatus .get (TIMEOUT_SECONDS , SECONDS );
433
455
}
434
456
435
457
@ Override
@@ -440,7 +462,7 @@ public void transportTerminated() {
440
462
}
441
463
442
464
public void awaitTermination () throws Exception {
443
- isTerminated .get (TIMEOUT_SECONDS , TimeUnit . SECONDS );
465
+ isTerminated .get (TIMEOUT_SECONDS , SECONDS );
444
466
}
445
467
446
468
@ Override
@@ -451,7 +473,7 @@ public void transportReady() {
451
473
}
452
474
453
475
public void awaitReady () throws Exception {
454
- isReady .get (TIMEOUT_SECONDS , TimeUnit . SECONDS );
476
+ isReady .get (TIMEOUT_SECONDS , SECONDS );
455
477
}
456
478
457
479
@ Override
@@ -567,25 +589,4 @@ public Status checkAuthorization(int uid) {
567
589
}
568
590
}
569
591
}
570
-
571
- /** An AsyncSecurityPolicy that lets a test specify the outcome of checkAuthorizationAsync(). */
572
- static class SettableAsyncSecurityPolicy extends AsyncSecurityPolicy {
573
- private SettableFuture <Status > result = SettableFuture .create ();
574
-
575
- public void clearAuthorizationResult () {
576
- result = SettableFuture .create ();
577
- }
578
-
579
- public boolean setAuthorizationResult (Status status ) {
580
- return result .set (status );
581
- }
582
-
583
- public boolean setAuthorizationException (Throwable t ) {
584
- return result .setException (t );
585
- }
586
-
587
- public ListenableFuture <Status > checkAuthorizationAsync (int uid ) {
588
- return Futures .nonCancellationPropagating (result );
589
- }
590
- }
591
592
}
0 commit comments