1 /* 2 * Copyright 2016 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.cronet; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertTrue; 21 import static org.mockito.Mockito.any; 22 import static org.mockito.Mockito.mock; 23 import static org.mockito.Mockito.times; 24 import static org.mockito.Mockito.verify; 25 import static org.mockito.Mockito.when; 26 27 import io.grpc.Attributes; 28 import io.grpc.CallCredentials; 29 import io.grpc.CallOptions; 30 import io.grpc.Metadata; 31 import io.grpc.MethodDescriptor; 32 import io.grpc.SecurityLevel; 33 import io.grpc.Status; 34 import io.grpc.cronet.CronetChannelBuilder.StreamBuilderFactory; 35 import io.grpc.internal.ClientStreamListener; 36 import io.grpc.internal.ManagedClientTransport; 37 import io.grpc.internal.TransportTracer; 38 import io.grpc.testing.TestMethodDescriptors; 39 import java.net.InetSocketAddress; 40 import java.util.concurrent.Executor; 41 import org.chromium.net.BidirectionalStream; 42 import org.junit.Before; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 import org.mockito.ArgumentCaptor; 46 import org.mockito.Mock; 47 import org.mockito.MockitoAnnotations; 48 import org.robolectric.RobolectricTestRunner; 49 50 @RunWith(RobolectricTestRunner.class) 51 public final class CronetClientTransportTest { 52 53 private static final String AUTHORITY = "test.example.com"; 54 55 private CronetClientTransport transport; 56 @Mock private StreamBuilderFactory streamFactory; 57 @Mock private Executor executor; 58 private MethodDescriptor<Void, Void> descriptor = TestMethodDescriptors.voidMethod(); 59 @Mock private ManagedClientTransport.Listener clientTransportListener; 60 @Mock private BidirectionalStream.Builder builder; 61 62 @Before setUp()63 public void setUp() { 64 MockitoAnnotations.initMocks(this); 65 66 transport = 67 new CronetClientTransport( 68 streamFactory, 69 new InetSocketAddress("localhost", 443), 70 AUTHORITY, 71 null, 72 executor, 73 5000, 74 false, 75 TransportTracer.getDefaultFactory().create()); 76 Runnable callback = transport.start(clientTransportListener); 77 assertTrue(callback != null); 78 callback.run(); 79 verify(clientTransportListener).transportReady(); 80 } 81 82 @Test transportAttributes()83 public void transportAttributes() { 84 Attributes attrs = transport.getAttributes(); 85 assertEquals(AUTHORITY, attrs.get(CallCredentials.ATTR_AUTHORITY)); 86 assertEquals( 87 SecurityLevel.PRIVACY_AND_INTEGRITY, attrs.get(CallCredentials.ATTR_SECURITY_LEVEL)); 88 } 89 90 @Test shutdownTransport()91 public void shutdownTransport() throws Exception { 92 CronetClientStream stream1 = 93 transport.newStream(descriptor, new Metadata(), CallOptions.DEFAULT); 94 CronetClientStream stream2 = 95 transport.newStream(descriptor, new Metadata(), CallOptions.DEFAULT); 96 97 // Create a transport and start two streams on it. 98 ArgumentCaptor<BidirectionalStream.Callback> callbackCaptor = 99 ArgumentCaptor.forClass(BidirectionalStream.Callback.class); 100 when(streamFactory.newBidirectionalStreamBuilder( 101 any(String.class), callbackCaptor.capture(), any(Executor.class))) 102 .thenReturn(builder); 103 BidirectionalStream cronetStream1 = mock(BidirectionalStream.class); 104 when(builder.build()).thenReturn(cronetStream1); 105 stream1.start(mock(ClientStreamListener.class)); 106 BidirectionalStream.Callback callback1 = callbackCaptor.getValue(); 107 108 BidirectionalStream cronetStream2 = mock(BidirectionalStream.class); 109 when(builder.build()).thenReturn(cronetStream2); 110 stream2.start(mock(ClientStreamListener.class)); 111 BidirectionalStream.Callback callback2 = callbackCaptor.getValue(); 112 // Shut down the transport. transportShutdown should be called immediately. 113 transport.shutdown(); 114 verify(clientTransportListener).transportShutdown(any(Status.class)); 115 // Have two live streams. Transport has not been terminated. 116 verify(clientTransportListener, times(0)).transportTerminated(); 117 118 callback1.onCanceled(cronetStream1, null); 119 // Still has one live stream 120 verify(clientTransportListener, times(0)).transportTerminated(); 121 callback2.onCanceled(cronetStream1, null); 122 // All streams are gone now. 123 verify(clientTransportListener, times(1)).transportTerminated(); 124 } 125 } 126