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 ;
30
29
import com .google .errorprone .annotations .CanIgnoreReturnValue ;
31
30
import com .google .errorprone .annotations .concurrent .GuardedBy ;
39
38
import io .grpc .Status ;
40
39
import io .grpc .Status .Code ;
41
40
import io .grpc .binder .AndroidComponentAddress ;
42
- import io .grpc .binder .AsyncSecurityPolicy ;
43
41
import io .grpc .binder .BinderServerBuilder ;
44
42
import io .grpc .binder .HostServices ;
45
43
import io .grpc .binder .SecurityPolicy ;
46
44
import io .grpc .binder .internal .OneWayBinderProxies .BlackHoleOneWayBinderProxy ;
47
45
import io .grpc .binder .internal .OneWayBinderProxies .BlockingBinderDecorator ;
48
46
import io .grpc .binder .internal .OneWayBinderProxies .ThrowingOneWayBinderProxy ;
47
+ import io .grpc .binder .internal .SettableAsyncSecurityPolicy .AuthRequest ;
49
48
import io .grpc .internal .ClientStream ;
50
49
import io .grpc .internal .ClientStreamListener ;
51
50
import io .grpc .internal .ClientTransportFactory .ClientTransportOptions ;
64
63
import java .util .concurrent .Executors ;
65
64
import java .util .concurrent .LinkedBlockingQueue ;
66
65
import java .util .concurrent .ScheduledExecutorService ;
67
- import java .util .concurrent .TimeUnit ;
68
66
import javax .annotation .Nullable ;
69
67
import org .junit .After ;
70
68
import org .junit .Before ;
@@ -193,7 +191,7 @@ public void tearDown() throws Exception {
193
191
private static void shutdownAndTerminate (ExecutorService executorService )
194
192
throws InterruptedException {
195
193
executorService .shutdownNow ();
196
- if (!executorService .awaitTermination (TIMEOUT_SECONDS , TimeUnit . SECONDS )) {
194
+ if (!executorService .awaitTermination (TIMEOUT_SECONDS , SECONDS )) {
197
195
throw new AssertionError ("executor failed to terminate promptly" );
198
196
}
199
197
}
@@ -375,26 +373,32 @@ public void testBlackHoleEndpointConnectTimeout() throws Exception {
375
373
376
374
@ Test
377
375
public void testBlackHoleSecurityPolicyConnectTimeout () throws Exception {
376
+ SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy ();
378
377
transport =
379
378
new BinderClientTransportBuilder ()
380
- .setSecurityPolicy (blockingSecurityPolicy )
379
+ .setSecurityPolicy (securityPolicy )
381
380
.setReadyTimeoutMillis (1_234 )
382
381
.build ();
383
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
+
384
386
Status transportStatus = transportListener .awaitShutdown ();
385
387
assertThat (transportStatus .getCode ()).isEqualTo (Code .DEADLINE_EXCEEDED );
386
388
assertThat (transportStatus .getDescription ()).contains ("1234" );
387
389
transportListener .awaitTermination ();
388
- blockingSecurityPolicy .provideNextCheckAuthorizationResult (Status .OK );
390
+
391
+ // If the transport gave up waiting on auth, it should cancel its request.
392
+ assertThat (authRequest .isCancelled ()).isTrue ();
389
393
}
390
394
391
395
@ Test
392
396
public void testAsyncSecurityPolicyFailure () throws Exception {
393
397
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy ();
394
398
transport = new BinderClientTransportBuilder ().setSecurityPolicy (securityPolicy ).build ();
395
399
RuntimeException exception = new NullPointerException ();
396
- securityPolicy .setAuthorizationException (exception );
397
400
transport .start (transportListener ).run ();
401
+ securityPolicy .takeNextAuthRequest (TIMEOUT_SECONDS , SECONDS ).setResult (exception );
398
402
Status transportStatus = transportListener .awaitShutdown ();
399
403
assertThat (transportStatus .getCode ()).isEqualTo (Code .INTERNAL );
400
404
assertThat (transportStatus .getCause ()).isEqualTo (exception );
@@ -405,13 +409,27 @@ public void testAsyncSecurityPolicyFailure() throws Exception {
405
409
public void testAsyncSecurityPolicySuccess () throws Exception {
406
410
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy ();
407
411
transport = new BinderClientTransportBuilder ().setSecurityPolicy (securityPolicy ).build ();
408
- securityPolicy .setAuthorizationResult (Status .PERMISSION_DENIED );
409
412
transport .start (transportListener ).run ();
413
+ securityPolicy
414
+ .takeNextAuthRequest (TIMEOUT_SECONDS , SECONDS )
415
+ .setResult (Status .PERMISSION_DENIED );
410
416
Status transportStatus = transportListener .awaitShutdown ();
411
417
assertThat (transportStatus .getCode ()).isEqualTo (Code .PERMISSION_DENIED );
412
418
transportListener .awaitTermination ();
413
419
}
414
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
+
415
433
private static void startAndAwaitReady (
416
434
BinderTransport .BinderClientTransport transport , TestTransportListener transportListener )
417
435
throws Exception {
@@ -433,7 +451,7 @@ public void transportShutdown(Status shutdownStatus) {
433
451
}
434
452
435
453
public Status awaitShutdown () throws Exception {
436
- return shutdownStatus .get (TIMEOUT_SECONDS , TimeUnit . SECONDS );
454
+ return shutdownStatus .get (TIMEOUT_SECONDS , SECONDS );
437
455
}
438
456
439
457
@ Override
@@ -444,7 +462,7 @@ public void transportTerminated() {
444
462
}
445
463
446
464
public void awaitTermination () throws Exception {
447
- isTerminated .get (TIMEOUT_SECONDS , TimeUnit . SECONDS );
465
+ isTerminated .get (TIMEOUT_SECONDS , SECONDS );
448
466
}
449
467
450
468
@ Override
@@ -455,7 +473,7 @@ public void transportReady() {
455
473
}
456
474
457
475
public void awaitReady () throws Exception {
458
- isReady .get (TIMEOUT_SECONDS , TimeUnit . SECONDS );
476
+ isReady .get (TIMEOUT_SECONDS , SECONDS );
459
477
}
460
478
461
479
@ Override
@@ -571,25 +589,4 @@ public Status checkAuthorization(int uid) {
571
589
}
572
590
}
573
591
}
574
-
575
- /** An AsyncSecurityPolicy that lets a test specify the outcome of checkAuthorizationAsync(). */
576
- static class SettableAsyncSecurityPolicy extends AsyncSecurityPolicy {
577
- private SettableFuture <Status > result = SettableFuture .create ();
578
-
579
- public void clearAuthorizationResult () {
580
- result = SettableFuture .create ();
581
- }
582
-
583
- public boolean setAuthorizationResult (Status status ) {
584
- return result .set (status );
585
- }
586
-
587
- public boolean setAuthorizationException (Throwable t ) {
588
- return result .setException (t );
589
- }
590
-
591
- public ListenableFuture <Status > checkAuthorizationAsync (int uid ) {
592
- return Futures .nonCancellationPropagating (result );
593
- }
594
- }
595
592
}
0 commit comments