1818
1919import static com .google .common .base .Preconditions .checkNotNull ;
2020import static com .google .common .truth .Truth .assertThat ;
21+ import static org .mockito .AdditionalAnswers .delegatesTo ;
2122import static org .mockito .ArgumentMatchers .any ;
2223import static org .mockito .ArgumentMatchers .anyString ;
2324import static org .mockito .ArgumentMatchers .argThat ;
5051import io .grpc .LoadBalancer .Subchannel ;
5152import io .grpc .LoadBalancer .SubchannelPicker ;
5253import io .grpc .LoadBalancer .SubchannelStateListener ;
53- import io .grpc .LongCounterMetricInstrument ;
5454import io .grpc .ManagedChannel ;
5555import io .grpc .ManagedChannelBuilder ;
5656import io .grpc .Metadata ;
5757import io .grpc .MethodDescriptor ;
58- import io .grpc .MethodDescriptor .Marshaller ;
5958import io .grpc .MethodDescriptor .MethodType ;
59+ import io .grpc .MetricInstrument ;
6060import io .grpc .MetricRecorder ;
61+ import io .grpc .MetricSink ;
6162import io .grpc .NameResolver .ConfigOrError ;
63+ import io .grpc .NoopMetricSink ;
64+ import io .grpc .ServerCall ;
65+ import io .grpc .ServerServiceDefinition ;
6266import io .grpc .Status ;
6367import io .grpc .Status .Code ;
6468import io .grpc .SynchronizationContext ;
6771import io .grpc .internal .FakeClock ;
6872import io .grpc .internal .JsonParser ;
6973import io .grpc .internal .PickSubchannelArgsImpl ;
74+ import io .grpc .internal .testing .StreamRecorder ;
7075import io .grpc .lookup .v1 .RouteLookupServiceGrpc ;
7176import io .grpc .rls .RlsLoadBalancer .CachingRlsLbClientBuilderProvider ;
7277import io .grpc .rls .RlsProtoConverters .RouteLookupResponseConverter ;
7378import io .grpc .rls .RlsProtoData .RouteLookupRequest ;
7479import io .grpc .rls .RlsProtoData .RouteLookupResponse ;
80+ import io .grpc .stub .ClientCalls ;
7581import io .grpc .stub .StreamObserver ;
7682import io .grpc .testing .GrpcCleanupRule ;
83+ import io .grpc .testing .TestMethodDescriptors ;
7784import java .io .IOException ;
7885import java .lang .Thread .UncaughtExceptionHandler ;
7986import java .net .SocketAddress ;
87+ import java .util .Arrays ;
8088import java .util .Collections ;
8189import java .util .Deque ;
8290import java .util .LinkedList ;
@@ -125,12 +133,10 @@ public void uncaughtException(Thread t, Throwable e) {
125133 private final Deque <FakeSubchannel > subchannels = new LinkedList <>();
126134 private final FakeThrottler fakeThrottler = new FakeThrottler ();
127135 private final String channelTarget = "channelTarget" ;
128- @ Mock
129- private Marshaller <Object > mockMarshaller ;
130136 @ Captor
131137 private ArgumentCaptor <SubchannelPicker > pickerCaptor ;
132- private MethodDescriptor <Object , Object > fakeSearchMethod ;
133- private MethodDescriptor <Object , Object > fakeRescueMethod ;
138+ private MethodDescriptor <Void , Void > fakeSearchMethod ;
139+ private MethodDescriptor <Void , Void > fakeRescueMethod ;
134140 private RlsLoadBalancer rlsLb ;
135141 private String defaultTarget = "defaultTarget" ;
136142 private PickSubchannelArgs searchSubchannelArgs ;
@@ -139,17 +145,17 @@ public void uncaughtException(Thread t, Throwable e) {
139145 @ Before
140146 public void setUp () {
141147 fakeSearchMethod =
142- MethodDescriptor .newBuilder ()
148+ MethodDescriptor .< Void , Void > newBuilder ()
143149 .setFullMethodName ("com.google/Search" )
144- .setRequestMarshaller (mockMarshaller )
145- .setResponseMarshaller (mockMarshaller )
150+ .setRequestMarshaller (TestMethodDescriptors . voidMarshaller () )
151+ .setResponseMarshaller (TestMethodDescriptors . voidMarshaller () )
146152 .setType (MethodType .CLIENT_STREAMING )
147153 .build ();
148154 fakeRescueMethod =
149- MethodDescriptor .newBuilder ()
155+ MethodDescriptor .< Void , Void > newBuilder ()
150156 .setFullMethodName ("com.google/Rescue" )
151- .setRequestMarshaller (mockMarshaller )
152- .setResponseMarshaller (mockMarshaller )
157+ .setRequestMarshaller (TestMethodDescriptors . voidMarshaller () )
158+ .setResponseMarshaller (TestMethodDescriptors . voidMarshaller () )
153159 .setType (MethodType .UNARY )
154160 .build ();
155161 fakeRlsServerImpl .setLookupTable (
@@ -282,6 +288,44 @@ public void lb_working_withDefaultTarget_rlsResponding() throws Exception {
282288 verifyNoMoreInteractions (mockMetricRecorder );
283289 }
284290
291+ @ Test
292+ public void metricsWithRealChannel () throws Exception {
293+ grpcCleanupRule .register (
294+ InProcessServerBuilder .forName ("fake-bigtable.googleapis.com" )
295+ .addService (ServerServiceDefinition .builder ("com.google" )
296+ .addMethod (fakeSearchMethod , (call , headers ) -> {
297+ call .sendHeaders (new Metadata ());
298+ call .sendMessage (null );
299+ call .close (Status .OK , new Metadata ());
300+ return new ServerCall .Listener <Void >() {};
301+ })
302+ .build ())
303+ .directExecutor ()
304+ .build ()
305+ .start ());
306+ MetricSink metrics = mock (MetricSink .class , delegatesTo (new NoopMetricSink ()));
307+ ManagedChannel channel = grpcCleanupRule .register (
308+ InProcessChannelBuilder .forName ("fake-bigtable.googleapis.com" )
309+ .defaultServiceConfig (parseJson (getServiceConfigJsonStr ()))
310+ .addMetricSink (metrics )
311+ .directExecutor ()
312+ .build ());
313+
314+ StreamRecorder <Void > recorder = StreamRecorder .create ();
315+ StreamObserver <Void > requestObserver = ClientCalls .asyncClientStreamingCall (
316+ channel .newCall (fakeSearchMethod , CallOptions .DEFAULT ), recorder );
317+ requestObserver .onCompleted ();
318+ assertThat (recorder .awaitCompletion (10 , TimeUnit .SECONDS )).isTrue ();
319+ assertThat (recorder .getError ()).isNull ();
320+
321+ verify (metrics ).addLongCounter (
322+ eqMetricInstrumentName ("grpc.lb.rls.default_target_picks" ),
323+ eq (1L ),
324+ eq (Arrays .asList ("directaddress:///fake-bigtable.googleapis.com" , "localhost:8972" ,
325+ "defaultTarget" , "complete" )),
326+ eq (Arrays .asList ()));
327+ }
328+
285329 @ Test
286330 public void lb_working_withoutDefaultTarget_noRlsResponse () throws Exception {
287331 defaultTarget = "" ;
@@ -498,7 +542,7 @@ private PickResult markReadyAndGetPickResult(InOrder inOrder,
498542
499543 private void deliverResolvedAddresses () throws Exception {
500544 ConfigOrError parsedConfigOrError =
501- provider .parseLoadBalancingPolicyConfig (getServiceConfig ( ));
545+ provider .parseLoadBalancingPolicyConfig (parseJson ( getLbConfigJsonStr () ));
502546 assertThat (parsedConfigOrError .getConfig ()).isNotNull ();
503547 rlsLb .acceptResolvedAddresses (ResolvedAddresses .newBuilder ()
504548 .setAddresses (ImmutableList .of (new EquivalentAddressGroup (mock (SocketAddress .class ))))
@@ -508,13 +552,24 @@ private void deliverResolvedAddresses() throws Exception {
508552 }
509553
510554 @ SuppressWarnings ("unchecked" )
511- private Map <String , Object > getServiceConfig () throws IOException {
512- String serviceConfig = "{"
555+ private Map <String , Object > parseJson (String json ) throws IOException {
556+ return (Map <String , Object >) JsonParser .parse (json );
557+ }
558+
559+ private String getServiceConfigJsonStr () {
560+ return "{"
561+ + " \" loadBalancingConfig\" : [{"
562+ + " \" rls_experimental\" : " + getLbConfigJsonStr ()
563+ + " }]"
564+ + "}" ;
565+ }
566+
567+ private String getLbConfigJsonStr () {
568+ return "{"
513569 + " \" routeLookupConfig\" : " + getRlsConfigJsonStr () + ", "
514570 + " \" childPolicy\" : [{\" pick_first\" : {}}],"
515571 + " \" childPolicyConfigTargetFieldName\" : \" serviceName\" "
516572 + "}" ;
517- return (Map <String , Object >) JsonParser .parse (serviceConfig );
518573 }
519574
520575 private String getRlsConfigJsonStr () {
@@ -558,12 +613,7 @@ private void verifyLongCounterAdd(String name, int times, long value,
558613 String dataPlaneTargetLabel , String pickResult ) {
559614 // TODO: support the "grpc.target" label once available.
560615 verify (mockMetricRecorder , times (times )).addLongCounter (
561- argThat (new ArgumentMatcher <LongCounterMetricInstrument >() {
562- @ Override
563- public boolean matches (LongCounterMetricInstrument longCounterInstrument ) {
564- return longCounterInstrument .getName ().equals (name );
565- }
566- }), eq (value ),
616+ eqMetricInstrumentName (name ), eq (value ),
567617 eq (Lists .newArrayList (channelTarget , "localhost:8972" , dataPlaneTargetLabel , pickResult )),
568618 eq (Lists .newArrayList ()));
569619 }
@@ -572,16 +622,21 @@ public boolean matches(LongCounterMetricInstrument longCounterInstrument) {
572622 private void verifyFailedPicksCounterAdd (int times , long value ) {
573623 // TODO: support the "grpc.target" label once available.
574624 verify (mockMetricRecorder , times (times )).addLongCounter (
575- argThat (new ArgumentMatcher <LongCounterMetricInstrument >() {
576- @ Override
577- public boolean matches (LongCounterMetricInstrument longCounterInstrument ) {
578- return longCounterInstrument .getName ().equals ("grpc.lb.rls.failed_picks" );
579- }
580- }), eq (value ),
625+ eqMetricInstrumentName ("grpc.lb.rls.failed_picks" ), eq (value ),
581626 eq (Lists .newArrayList (channelTarget , "localhost:8972" )),
582627 eq (Lists .newArrayList ()));
583628 }
584629
630+ @ SuppressWarnings ("TypeParameterUnusedInFormals" )
631+ private <T extends MetricInstrument > T eqMetricInstrumentName (String name ) {
632+ return argThat (new ArgumentMatcher <T >() {
633+ @ Override
634+ public boolean matches (T instrument ) {
635+ return instrument .getName ().equals (name );
636+ }
637+ });
638+ }
639+
585640 private PickSubchannelArgs newPickSubchannelArgs (MethodDescriptor <?, ?> method ) {
586641 return new PickSubchannelArgsImpl (
587642 method , new Metadata (), CallOptions .DEFAULT , new PickDetailsConsumer () {});
0 commit comments