1 /*
2  * Copyright 2018 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.services;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static io.grpc.InternalChannelz.id;
21 import static org.junit.Assert.assertEquals;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.when;
24 
25 import com.google.common.base.Charsets;
26 import com.google.common.collect.ImmutableList;
27 import com.google.common.collect.ImmutableMap;
28 import com.google.protobuf.Any;
29 import com.google.protobuf.ByteString;
30 import com.google.protobuf.Int64Value;
31 import com.google.protobuf.Message;
32 import com.google.protobuf.util.Durations;
33 import com.google.protobuf.util.Timestamps;
34 import io.grpc.ConnectivityState;
35 import io.grpc.InternalChannelz;
36 import io.grpc.InternalChannelz.ChannelStats;
37 import io.grpc.InternalChannelz.ChannelTrace.Event;
38 import io.grpc.InternalChannelz.ChannelTrace.Event.Severity;
39 import io.grpc.InternalChannelz.RootChannelList;
40 import io.grpc.InternalChannelz.ServerList;
41 import io.grpc.InternalChannelz.ServerSocketsList;
42 import io.grpc.InternalChannelz.ServerStats;
43 import io.grpc.InternalChannelz.SocketOptions;
44 import io.grpc.InternalChannelz.SocketStats;
45 import io.grpc.InternalInstrumented;
46 import io.grpc.InternalWithLogId;
47 import io.grpc.channelz.v1.Address;
48 import io.grpc.channelz.v1.Address.OtherAddress;
49 import io.grpc.channelz.v1.Address.TcpIpAddress;
50 import io.grpc.channelz.v1.Address.UdsAddress;
51 import io.grpc.channelz.v1.Channel;
52 import io.grpc.channelz.v1.ChannelConnectivityState;
53 import io.grpc.channelz.v1.ChannelConnectivityState.State;
54 import io.grpc.channelz.v1.ChannelData;
55 import io.grpc.channelz.v1.ChannelRef;
56 import io.grpc.channelz.v1.ChannelTrace;
57 import io.grpc.channelz.v1.ChannelTraceEvent;
58 import io.grpc.channelz.v1.GetChannelRequest;
59 import io.grpc.channelz.v1.GetServerSocketsResponse;
60 import io.grpc.channelz.v1.GetServersResponse;
61 import io.grpc.channelz.v1.GetTopChannelsResponse;
62 import io.grpc.channelz.v1.Security;
63 import io.grpc.channelz.v1.Security.OtherSecurity;
64 import io.grpc.channelz.v1.Security.Tls;
65 import io.grpc.channelz.v1.Server;
66 import io.grpc.channelz.v1.ServerData;
67 import io.grpc.channelz.v1.ServerRef;
68 import io.grpc.channelz.v1.Socket;
69 import io.grpc.channelz.v1.SocketData;
70 import io.grpc.channelz.v1.SocketOption;
71 import io.grpc.channelz.v1.SocketOptionLinger;
72 import io.grpc.channelz.v1.SocketOptionTcpInfo;
73 import io.grpc.channelz.v1.SocketOptionTimeout;
74 import io.grpc.channelz.v1.SocketRef;
75 import io.grpc.channelz.v1.Subchannel;
76 import io.grpc.channelz.v1.SubchannelRef;
77 import io.grpc.services.ChannelzTestHelper.TestChannel;
78 import io.grpc.services.ChannelzTestHelper.TestListenSocket;
79 import io.grpc.services.ChannelzTestHelper.TestServer;
80 import io.grpc.services.ChannelzTestHelper.TestSocket;
81 import io.netty.channel.unix.DomainSocketAddress;
82 import java.net.Inet4Address;
83 import java.net.InetSocketAddress;
84 import java.net.SocketAddress;
85 import java.security.cert.Certificate;
86 import java.util.Arrays;
87 import java.util.Collections;
88 import java.util.Map.Entry;
89 import org.junit.Test;
90 import org.junit.runner.RunWith;
91 import org.junit.runners.JUnit4;
92 
93 @RunWith(JUnit4.class)
94 public final class ChannelzProtoUtilTest {
95 
96   private final TestChannel channel = new TestChannel();
97   private final ChannelRef channelRef = ChannelRef
98       .newBuilder()
99       .setName(channel.toString())
100       .setChannelId(channel.getLogId().getId())
101       .build();
102   private final ChannelData channelData = ChannelData
103       .newBuilder()
104       .setTarget("sometarget")
105       .setState(ChannelConnectivityState.newBuilder().setState(State.READY))
106       .setCallsStarted(1)
107       .setCallsSucceeded(2)
108       .setCallsFailed(3)
109       .setLastCallStartedTimestamp(Timestamps.fromNanos(4))
110       .build();
111   private final Channel channelProto = Channel
112       .newBuilder()
113       .setRef(channelRef)
114       .setData(channelData)
115       .build();
116 
117   private final TestChannel subchannel = new TestChannel();
118   private final SubchannelRef subchannelRef = SubchannelRef
119       .newBuilder()
120       .setName(subchannel.toString())
121       .setSubchannelId(subchannel.getLogId().getId())
122       .build();
123   private final ChannelData subchannelData = ChannelData
124       .newBuilder()
125       .setTarget("sometarget")
126       .setState(ChannelConnectivityState.newBuilder().setState(State.READY))
127       .setCallsStarted(1)
128       .setCallsSucceeded(2)
129       .setCallsFailed(3)
130       .setLastCallStartedTimestamp(Timestamps.fromNanos(4))
131       .build();
132   private final Subchannel subchannelProto = Subchannel
133         .newBuilder()
134         .setRef(subchannelRef)
135         .setData(subchannelData)
136         .build();
137 
138   private final TestServer server = new TestServer();
139   private final ServerRef serverRef = ServerRef
140       .newBuilder()
141       .setName(server.toString())
142       .setServerId(server.getLogId().getId())
143       .build();
144   private final ServerData serverData = ServerData
145       .newBuilder()
146       .setCallsStarted(1)
147       .setCallsSucceeded(2)
148       .setCallsFailed(3)
149       .setLastCallStartedTimestamp(Timestamps.fromNanos(4))
150       .build();
151   private final Server serverProto = Server
152       .newBuilder()
153       .setRef(serverRef)
154       .setData(serverData)
155       .build();
156 
157   private final SocketOption sockOptLingerDisabled = SocketOption
158       .newBuilder()
159       .setName("SO_LINGER")
160       .setAdditional(
161           Any.pack(SocketOptionLinger.getDefaultInstance()))
162       .build();
163 
164   private final SocketOption sockOptlinger10s = SocketOption
165       .newBuilder()
166       .setName("SO_LINGER")
167       .setAdditional(
168           Any.pack(SocketOptionLinger
169               .newBuilder()
170               .setActive(true)
171               .setDuration(Durations.fromSeconds(10))
172               .build()))
173       .build();
174 
175   private final SocketOption sockOptTimeout200ms = SocketOption
176       .newBuilder()
177       .setName("SO_TIMEOUT")
178       .setAdditional(
179           Any.pack(SocketOptionTimeout
180           .newBuilder()
181           .setDuration(Durations.fromMillis(200))
182           .build())
183       ).build();
184 
185   private final SocketOption sockOptAdditional = SocketOption
186       .newBuilder()
187       .setName("SO_MADE_UP_OPTION")
188       .setValue("some-made-up-value")
189       .build();
190 
191   private final InternalChannelz.TcpInfo channelzTcpInfo
192       = new InternalChannelz.TcpInfo.Builder()
193       .setState(70)
194       .setCaState(71)
195       .setRetransmits(72)
196       .setProbes(73)
197       .setBackoff(74)
198       .setOptions(75)
199       .setSndWscale(76)
200       .setRcvWscale(77)
201       .setRto(78)
202       .setAto(79)
203       .setSndMss(710)
204       .setRcvMss(711)
205       .setUnacked(712)
206       .setSacked(713)
207       .setLost(714)
208       .setRetrans(715)
209       .setFackets(716)
210       .setLastDataSent(717)
211       .setLastAckSent(718)
212       .setLastDataRecv(719)
213       .setLastAckRecv(720)
214       .setPmtu(721)
215       .setRcvSsthresh(722)
216       .setRtt(723)
217       .setRttvar(724)
218       .setSndSsthresh(725)
219       .setSndCwnd(726)
220       .setAdvmss(727)
221       .setReordering(728)
222       .build();
223 
224   private final SocketOption socketOptionTcpInfo = SocketOption
225       .newBuilder()
226       .setName("TCP_INFO")
227       .setAdditional(
228           Any.pack(
229               SocketOptionTcpInfo.newBuilder()
230                   .setTcpiState(70)
231                   .setTcpiCaState(71)
232                   .setTcpiRetransmits(72)
233                   .setTcpiProbes(73)
234                   .setTcpiBackoff(74)
235                   .setTcpiOptions(75)
236                   .setTcpiSndWscale(76)
237                   .setTcpiRcvWscale(77)
238                   .setTcpiRto(78)
239                   .setTcpiAto(79)
240                   .setTcpiSndMss(710)
241                   .setTcpiRcvMss(711)
242                   .setTcpiUnacked(712)
243                   .setTcpiSacked(713)
244                   .setTcpiLost(714)
245                   .setTcpiRetrans(715)
246                   .setTcpiFackets(716)
247                   .setTcpiLastDataSent(717)
248                   .setTcpiLastAckSent(718)
249                   .setTcpiLastDataRecv(719)
250                   .setTcpiLastAckRecv(720)
251                   .setTcpiPmtu(721)
252                   .setTcpiRcvSsthresh(722)
253                   .setTcpiRtt(723)
254                   .setTcpiRttvar(724)
255                   .setTcpiSndSsthresh(725)
256                   .setTcpiSndCwnd(726)
257                   .setTcpiAdvmss(727)
258                   .setTcpiReordering(728)
259                   .build()))
260       .build();
261 
262   private final TestListenSocket listenSocket = new TestListenSocket();
263   private final SocketRef listenSocketRef = SocketRef
264       .newBuilder()
265       .setName(listenSocket.toString())
266       .setSocketId(id(listenSocket))
267       .build();
268   private final Address listenAddress = Address
269       .newBuilder()
270       .setTcpipAddress(
271           TcpIpAddress
272               .newBuilder()
273               .setIpAddress(ByteString.copyFrom(
274                   ((InetSocketAddress) listenSocket.listenAddress).getAddress().getAddress()))
275               .setPort(1234))
276       .build();
277 
278   private final TestSocket socket = new TestSocket();
279   private final SocketRef socketRef = SocketRef
280       .newBuilder()
281       .setName(socket.toString())
282       .setSocketId(socket.getLogId().getId())
283       .build();
284   private final SocketData socketDataWithDataNoSockOpts = SocketData
285       .newBuilder()
286       .setStreamsStarted(1)
287       .setLastLocalStreamCreatedTimestamp(Timestamps.fromNanos(2))
288       .setLastRemoteStreamCreatedTimestamp(Timestamps.fromNanos(3))
289       .setStreamsSucceeded(4)
290       .setStreamsFailed(5)
291       .setMessagesSent(6)
292       .setMessagesReceived(7)
293       .setKeepAlivesSent(8)
294       .setLastMessageSentTimestamp(Timestamps.fromNanos(9))
295       .setLastMessageReceivedTimestamp(Timestamps.fromNanos(10))
296       .setLocalFlowControlWindow(Int64Value.newBuilder().setValue(11))
297       .setRemoteFlowControlWindow(Int64Value.newBuilder().setValue(12))
298       .build();
299   private final Address localAddress = Address
300       .newBuilder()
301       .setTcpipAddress(
302           TcpIpAddress
303               .newBuilder()
304               .setIpAddress(ByteString.copyFrom(
305                   ((InetSocketAddress) socket.local).getAddress().getAddress()))
306               .setPort(1000))
307       .build();
308   private final Address remoteAddress = Address
309       .newBuilder()
310       .setTcpipAddress(
311           TcpIpAddress
312               .newBuilder()
313               .setIpAddress(ByteString.copyFrom(
314                   ((InetSocketAddress) socket.remote).getAddress().getAddress()))
315               .setPort(1000))
316       .build();
317 
318   private final ChannelTrace channelTrace = ChannelTrace
319       .newBuilder()
320       .setNumEventsLogged(1234)
321       .setCreationTimestamp(Timestamps.fromNanos(1000))
322       .build();
323 
324   @Test
toChannelRef()325   public void toChannelRef() {
326     assertEquals(channelRef, ChannelzProtoUtil.toChannelRef(channel));
327   }
328 
329   @Test
toSubchannelRef()330   public void toSubchannelRef() {
331     assertEquals(subchannelRef, ChannelzProtoUtil.toSubchannelRef(subchannel));
332   }
333 
334   @Test
toServerRef()335   public void toServerRef() {
336     assertEquals(serverRef, ChannelzProtoUtil.toServerRef(server));
337   }
338 
339   @Test
toSocketRef()340   public void toSocketRef() {
341     assertEquals(socketRef, ChannelzProtoUtil.toSocketRef(socket));
342   }
343 
344   @Test
toState()345   public void toState() {
346     for (ConnectivityState connectivityState : ConnectivityState.values()) {
347       assertEquals(
348           connectivityState.name(),
349           ChannelzProtoUtil.toState(connectivityState).getValueDescriptor().getName());
350     }
351     assertEquals(State.UNKNOWN, ChannelzProtoUtil.toState(null));
352   }
353 
354   @Test
toSocket_withDataNoOptions()355   public void toSocket_withDataNoOptions() throws Exception {
356     assertEquals(
357         Socket
358             .newBuilder()
359             .setRef(socketRef)
360             .setLocal(localAddress)
361             .setRemote(remoteAddress)
362             .setData(socketDataWithDataNoSockOpts)
363             .build(),
364         ChannelzProtoUtil.toSocket(socket));
365   }
366 
367   @Test
toSocket_noDataWithOptions()368   public void toSocket_noDataWithOptions() throws Exception {
369     assertEquals(
370         Socket
371             .newBuilder()
372             .setRef(listenSocketRef)
373             .setLocal(listenAddress)
374             .setData(
375                 SocketData
376                     .newBuilder()
377                     .addOption(
378                         SocketOption
379                             .newBuilder()
380                             .setName("listen_option")
381                             .setValue("listen_option_value")))
382             .build(),
383         ChannelzProtoUtil.toSocket(listenSocket));
384   }
385 
386   @Test
toSocket_withDataWithOptions()387   public void toSocket_withDataWithOptions() throws Exception {
388     socket.socketOptions
389         = new SocketOptions(null, null, null, ImmutableMap.of("test_name", "test_value"));
390     assertEquals(
391         Socket
392             .newBuilder()
393             .setRef(socketRef)
394             .setLocal(localAddress)
395             .setRemote(remoteAddress)
396             .setData(
397                 SocketData
398                     .newBuilder(socketDataWithDataNoSockOpts)
399                     .addOption(
400                         SocketOption.newBuilder()
401                             .setName("test_name").setValue("test_value")))
402             .build(),
403         ChannelzProtoUtil.toSocket(socket));
404   }
405 
406   @Test
extractSocketData()407   public void extractSocketData() throws Exception {
408     // no options
409     assertEquals(
410         socketDataWithDataNoSockOpts,
411         ChannelzProtoUtil.extractSocketData(socket.getStats().get()));
412 
413     // with options
414     socket.socketOptions = toBuilder(socket.socketOptions)
415         .setSocketOptionLingerSeconds(10)
416         .setTcpInfo(channelzTcpInfo)
417         .build();
418     assertEquals(
419         socketDataWithDataNoSockOpts
420             .toBuilder()
421             .addOption(sockOptlinger10s)
422             .addOption(socketOptionTcpInfo)
423             .build(),
424         ChannelzProtoUtil.extractSocketData(socket.getStats().get()));
425   }
426 
427   @Test
toSocketData()428   public void toSocketData() throws Exception {
429     assertEquals(
430         socketDataWithDataNoSockOpts
431             .toBuilder()
432             .build(),
433         ChannelzProtoUtil.extractSocketData(socket.getStats().get()));
434   }
435 
436   @Test
socketSecurityTls()437   public void socketSecurityTls() throws Exception {
438     Certificate local = mock(Certificate.class);
439     Certificate remote = mock(Certificate.class);
440     when(local.getEncoded()).thenReturn("localcert".getBytes(Charsets.UTF_8));
441     when(remote.getEncoded()).thenReturn("remotecert".getBytes(Charsets.UTF_8));
442 
443     socket.security = new InternalChannelz.Security(
444         new InternalChannelz.Tls("TLS_NULL_WITH_NULL_NULL", local, remote));
445     assertEquals(
446         Security.newBuilder().setTls(
447             Tls.newBuilder()
448             .setStandardName("TLS_NULL_WITH_NULL_NULL")
449             .setLocalCertificate(ByteString.copyFrom("localcert", Charsets.UTF_8))
450             .setRemoteCertificate(ByteString.copyFrom("remotecert", Charsets.UTF_8)))
451         .build(),
452         ChannelzProtoUtil.toSocket(socket).getSecurity());
453 
454     socket.security = new InternalChannelz.Security(
455         new InternalChannelz.Tls("TLS_NULL_WITH_NULL_NULL", /*localCert=*/ null, remote));
456     assertEquals(
457         Security.newBuilder().setTls(
458             Tls.newBuilder()
459             .setStandardName("TLS_NULL_WITH_NULL_NULL")
460             .setRemoteCertificate(ByteString.copyFrom("remotecert", Charsets.UTF_8)))
461         .build(),
462         ChannelzProtoUtil.toSocket(socket).getSecurity());
463 
464     socket.security = new InternalChannelz.Security(
465         new InternalChannelz.Tls("TLS_NULL_WITH_NULL_NULL", local, /*remoteCert=*/ null));
466     assertEquals(
467         Security.newBuilder().setTls(
468             Tls.newBuilder()
469                 .setStandardName("TLS_NULL_WITH_NULL_NULL")
470                 .setLocalCertificate(ByteString.copyFrom("localcert", Charsets.UTF_8)))
471             .build(),
472             ChannelzProtoUtil.toSocket(socket).getSecurity());
473   }
474 
475   @Test
socketSecurityOther()476   public void socketSecurityOther() throws Exception {
477     // what is packed here is not important, just pick some proto message
478     Message contents = GetChannelRequest.newBuilder().setChannelId(1).build();
479     Any packed = Any.pack(contents);
480     socket.security
481         = new InternalChannelz.Security(
482             new InternalChannelz.OtherSecurity("other_security", packed));
483     assertEquals(
484         Security.newBuilder().setOther(
485             OtherSecurity.newBuilder().setName("other_security").setValue(packed))
486         .build(),
487         ChannelzProtoUtil.toSocket(socket).getSecurity());
488   }
489 
490   @Test
toAddress_inet()491   public void toAddress_inet() throws Exception {
492     InetSocketAddress inet4 = new InetSocketAddress(Inet4Address.getByName("10.0.0.1"), 1000);
493     assertEquals(
494         Address.newBuilder().setTcpipAddress(
495             TcpIpAddress
496                 .newBuilder()
497                 .setIpAddress(ByteString.copyFrom(inet4.getAddress().getAddress()))
498                 .setPort(1000))
499             .build(),
500         ChannelzProtoUtil.toAddress(inet4));
501   }
502 
503   @Test
toAddress_uds()504   public void toAddress_uds() throws Exception {
505     String path = "/tmp/foo";
506     DomainSocketAddress uds = new DomainSocketAddress(path);
507     assertEquals(
508         Address.newBuilder().setUdsAddress(
509             UdsAddress
510                 .newBuilder()
511                 .setFilename(path))
512             .build(),
513         ChannelzProtoUtil.toAddress(uds));
514   }
515 
516   @Test
toAddress_other()517   public void toAddress_other() throws Exception {
518     final String name = "my name";
519     SocketAddress other = new SocketAddress() {
520       @Override
521       public String toString() {
522         return name;
523       }
524     };
525     assertEquals(
526         Address.newBuilder().setOtherAddress(
527             OtherAddress
528                 .newBuilder()
529                 .setName(name))
530             .build(),
531         ChannelzProtoUtil.toAddress(other));
532   }
533 
534   @Test
toServer()535   public void toServer() throws Exception {
536     // no listen sockets
537     assertEquals(serverProto, ChannelzProtoUtil.toServer(server));
538 
539     // 1 listen socket
540     server.serverStats = toBuilder(server.serverStats)
541         .setListenSockets(ImmutableList.<InternalInstrumented<SocketStats>>of(listenSocket))
542         .build();
543     assertEquals(
544         serverProto
545             .toBuilder()
546             .addListenSocket(listenSocketRef)
547             .build(),
548         ChannelzProtoUtil.toServer(server));
549 
550     // multiple listen sockets
551     TestListenSocket otherListenSocket = new TestListenSocket();
552     SocketRef otherListenSocketRef = ChannelzProtoUtil.toSocketRef(otherListenSocket);
553     server.serverStats = toBuilder(server.serverStats)
554         .setListenSockets(
555             ImmutableList.<InternalInstrumented<SocketStats>>of(listenSocket, otherListenSocket))
556         .build();
557     assertEquals(
558         serverProto
559             .toBuilder()
560             .addListenSocket(listenSocketRef)
561             .addListenSocket(otherListenSocketRef)
562             .build(),
563         ChannelzProtoUtil.toServer(server));
564   }
565 
566   @Test
toServerData()567   public void toServerData() throws Exception {
568     assertEquals(serverData, ChannelzProtoUtil.toServerData(server.serverStats));
569   }
570 
571   @Test
toChannel()572   public void toChannel() throws Exception {
573     assertEquals(channelProto, ChannelzProtoUtil.toChannel(channel));
574 
575     channel.stats = toBuilder(channel.stats)
576         .setSubchannels(ImmutableList.<InternalWithLogId>of(subchannel))
577         .build();
578 
579     assertEquals(
580         channelProto
581             .toBuilder()
582             .addSubchannelRef(subchannelRef)
583             .build(),
584         ChannelzProtoUtil.toChannel(channel));
585 
586     TestChannel otherSubchannel = new TestChannel();
587     channel.stats = toBuilder(channel.stats)
588         .setSubchannels(ImmutableList.<InternalWithLogId>of(subchannel, otherSubchannel))
589         .build();
590     assertEquals(
591         channelProto
592             .toBuilder()
593             .addSubchannelRef(subchannelRef)
594             .addSubchannelRef(ChannelzProtoUtil.toSubchannelRef(otherSubchannel))
595             .build(),
596         ChannelzProtoUtil.toChannel(channel));
597   }
598 
599   @Test
extractChannelData()600   public void extractChannelData() {
601     assertEquals(channelData, ChannelzProtoUtil.extractChannelData(channel.stats));
602   }
603 
604   @Test
toSubchannel_noChildren()605   public void toSubchannel_noChildren() throws Exception {
606     assertEquals(
607         subchannelProto,
608         ChannelzProtoUtil.toSubchannel(subchannel));
609   }
610 
611   @Test
toSubchannel_socketChildren()612   public void toSubchannel_socketChildren() throws Exception {
613     subchannel.stats = toBuilder(subchannel.stats)
614         .setSockets(ImmutableList.<InternalWithLogId>of(socket))
615         .build();
616 
617     assertEquals(
618         subchannelProto.toBuilder()
619             .addSocketRef(socketRef)
620             .build(),
621         ChannelzProtoUtil.toSubchannel(subchannel));
622 
623     TestSocket otherSocket = new TestSocket();
624     subchannel.stats = toBuilder(subchannel.stats)
625         .setSockets(ImmutableList.<InternalWithLogId>of(socket, otherSocket))
626         .build();
627     assertEquals(
628         subchannelProto
629             .toBuilder()
630             .addSocketRef(socketRef)
631             .addSocketRef(ChannelzProtoUtil.toSocketRef(otherSocket))
632             .build(),
633         ChannelzProtoUtil.toSubchannel(subchannel));
634   }
635 
636   @Test
toSubchannel_subchannelChildren()637   public void toSubchannel_subchannelChildren() throws Exception {
638     TestChannel subchannel1 = new TestChannel();
639     subchannel.stats = toBuilder(subchannel.stats)
640         .setSubchannels(ImmutableList.<InternalWithLogId>of(subchannel1))
641         .build();
642     assertEquals(
643         subchannelProto.toBuilder()
644             .addSubchannelRef(ChannelzProtoUtil.toSubchannelRef(subchannel1))
645             .build(),
646         ChannelzProtoUtil.toSubchannel(subchannel));
647 
648     TestChannel subchannel2 = new TestChannel();
649     subchannel.stats = toBuilder(subchannel.stats)
650         .setSubchannels(ImmutableList.<InternalWithLogId>of(subchannel1, subchannel2))
651         .build();
652     assertEquals(
653         subchannelProto
654             .toBuilder()
655             .addSubchannelRef(ChannelzProtoUtil.toSubchannelRef(subchannel1))
656             .addSubchannelRef(ChannelzProtoUtil.toSubchannelRef(subchannel2))
657             .build(),
658         ChannelzProtoUtil.toSubchannel(subchannel));
659   }
660 
661   @Test
toGetTopChannelsResponse()662   public void toGetTopChannelsResponse() {
663     // empty results
664     assertEquals(
665         GetTopChannelsResponse.newBuilder().setEnd(true).build(),
666         ChannelzProtoUtil.toGetTopChannelResponse(
667             new RootChannelList(
668                 Collections.<InternalInstrumented<ChannelStats>>emptyList(), true)));
669 
670     // 1 result, paginated
671     assertEquals(
672         GetTopChannelsResponse
673             .newBuilder()
674             .addChannel(channelProto)
675             .build(),
676         ChannelzProtoUtil.toGetTopChannelResponse(
677             new RootChannelList(
678                 ImmutableList.<InternalInstrumented<ChannelStats>>of(channel), false)));
679 
680     // 1 result, end
681     assertEquals(
682         GetTopChannelsResponse
683             .newBuilder()
684             .addChannel(channelProto)
685             .setEnd(true)
686             .build(),
687         ChannelzProtoUtil.toGetTopChannelResponse(
688             new RootChannelList(
689                 ImmutableList.<InternalInstrumented<ChannelStats>>of(channel), true)));
690 
691     // 2 results, end
692     TestChannel channel2 = new TestChannel();
693     assertEquals(
694         GetTopChannelsResponse
695             .newBuilder()
696             .addChannel(channelProto)
697             .addChannel(ChannelzProtoUtil.toChannel(channel2))
698             .setEnd(true)
699             .build(),
700         ChannelzProtoUtil.toGetTopChannelResponse(
701             new RootChannelList(
702                 ImmutableList.<InternalInstrumented<ChannelStats>>of(channel, channel2), true)));
703   }
704 
705   @Test
toGetServersResponse()706   public void toGetServersResponse() {
707     // empty results
708     assertEquals(
709         GetServersResponse.getDefaultInstance(),
710         ChannelzProtoUtil.toGetServersResponse(
711             new ServerList(Collections.<InternalInstrumented<ServerStats>>emptyList(), false)));
712 
713     // 1 result, paginated
714     assertEquals(
715         GetServersResponse
716             .newBuilder()
717             .addServer(serverProto)
718             .build(),
719         ChannelzProtoUtil.toGetServersResponse(
720             new ServerList(ImmutableList.<InternalInstrumented<ServerStats>>of(server), false)));
721 
722     // 1 result, end
723     assertEquals(
724         GetServersResponse
725             .newBuilder()
726             .addServer(serverProto)
727             .setEnd(true)
728             .build(),
729         ChannelzProtoUtil.toGetServersResponse(
730             new ServerList(ImmutableList.<InternalInstrumented<ServerStats>>of(server), true)));
731 
732     TestServer server2 = new TestServer();
733     // 2 results, end
734     assertEquals(
735         GetServersResponse
736             .newBuilder()
737             .addServer(serverProto)
738             .addServer(ChannelzProtoUtil.toServer(server2))
739             .setEnd(true)
740             .build(),
741         ChannelzProtoUtil.toGetServersResponse(
742             new ServerList(
743                 ImmutableList.<InternalInstrumented<ServerStats>>of(server, server2), true)));
744   }
745 
746   @Test
toGetServerSocketsResponse()747   public void toGetServerSocketsResponse() {
748     // empty results
749     assertEquals(
750         GetServerSocketsResponse.getDefaultInstance(),
751         ChannelzProtoUtil.toGetServerSocketsResponse(
752             new ServerSocketsList(Collections.<InternalWithLogId>emptyList(), false)));
753 
754     // 1 result, paginated
755     assertEquals(
756         GetServerSocketsResponse
757             .newBuilder()
758             .addSocketRef(socketRef)
759             .build(),
760         ChannelzProtoUtil.toGetServerSocketsResponse(
761             new ServerSocketsList(ImmutableList.<InternalWithLogId>of(socket), false)));
762 
763     // 1 result, end
764     assertEquals(
765         GetServerSocketsResponse
766             .newBuilder()
767             .addSocketRef(socketRef)
768             .setEnd(true)
769             .build(),
770         ChannelzProtoUtil.toGetServerSocketsResponse(
771             new ServerSocketsList(ImmutableList.<InternalWithLogId>of(socket), true)));
772 
773     TestSocket socket2 = new TestSocket();
774     // 2 results, end
775     assertEquals(
776         GetServerSocketsResponse
777             .newBuilder()
778             .addSocketRef(socketRef)
779             .addSocketRef(ChannelzProtoUtil.toSocketRef(socket2))
780             .setEnd(true)
781             .build(),
782         ChannelzProtoUtil.toGetServerSocketsResponse(
783             new ServerSocketsList(ImmutableList.<InternalWithLogId>of(socket, socket2), true)));
784   }
785 
786   @Test
toSocketOptionLinger()787   public void toSocketOptionLinger() {
788     assertEquals(sockOptLingerDisabled, ChannelzProtoUtil.toSocketOptionLinger(-1));
789     assertEquals(sockOptlinger10s, ChannelzProtoUtil.toSocketOptionLinger(10));
790   }
791 
792   @Test
toSocketOptionTimeout()793   public void toSocketOptionTimeout() {
794     assertEquals(
795         sockOptTimeout200ms, ChannelzProtoUtil.toSocketOptionTimeout("SO_TIMEOUT", 200));
796   }
797 
798   @Test
toSocketOptionAdditional()799   public void toSocketOptionAdditional() {
800     assertEquals(
801         sockOptAdditional,
802         ChannelzProtoUtil.toSocketOptionAdditional("SO_MADE_UP_OPTION", "some-made-up-value"));
803   }
804 
805   @Test
toSocketOptionTcpInfo()806   public void toSocketOptionTcpInfo() {
807     assertEquals(
808         socketOptionTcpInfo,
809         ChannelzProtoUtil.toSocketOptionTcpInfo(channelzTcpInfo));
810   }
811 
812   @Test
toSocketOptionsList()813   public void toSocketOptionsList() {
814     assertThat(
815         ChannelzProtoUtil.toSocketOptionsList(
816             new InternalChannelz.SocketOptions.Builder().build()))
817         .isEmpty();
818 
819     assertThat(
820         ChannelzProtoUtil.toSocketOptionsList(
821             new InternalChannelz.SocketOptions.Builder().setSocketOptionLingerSeconds(10).build()))
822         .containsExactly(sockOptlinger10s);
823 
824     assertThat(
825         ChannelzProtoUtil.toSocketOptionsList(
826             new InternalChannelz.SocketOptions.Builder().setSocketOptionTimeoutMillis(200).build()))
827         .containsExactly(sockOptTimeout200ms);
828 
829     assertThat(
830         ChannelzProtoUtil.toSocketOptionsList(
831             new InternalChannelz.SocketOptions
832                 .Builder()
833                 .addOption("SO_MADE_UP_OPTION", "some-made-up-value")
834                 .build()))
835         .containsExactly(sockOptAdditional);
836 
837     SocketOption otherOption = SocketOption
838         .newBuilder()
839         .setName("SO_MADE_UP_OPTION2")
840         .setValue("some-made-up-value2")
841         .build();
842     assertThat(
843         ChannelzProtoUtil.toSocketOptionsList(
844             new InternalChannelz.SocketOptions.Builder()
845                 .addOption("SO_MADE_UP_OPTION", "some-made-up-value")
846                 .addOption("SO_MADE_UP_OPTION2", "some-made-up-value2")
847                 .build()))
848         .containsExactly(sockOptAdditional, otherOption);
849   }
850 
851   @Test
channelTrace_withoutEvents()852   public void channelTrace_withoutEvents() {
853     ChannelStats stats = toBuilder(channel.stats)
854         .setChannelTrace(new InternalChannelz.ChannelTrace.Builder()
855             .setNumEventsLogged(1234)
856             .setCreationTimeNanos(1000)
857             .build())
858         .build();
859 
860     ChannelData protoStats = channelData.toBuilder().setTrace(channelTrace).build();
861     assertEquals(ChannelzProtoUtil.extractChannelData(stats), protoStats);
862   }
863 
864   @Test
channelTrace_withEvents()865   public void channelTrace_withEvents() {
866     Event event1 = new Event.Builder()
867         .setDescription("event1")
868         .setSeverity(Severity.CT_ERROR)
869         .setTimestampNanos(12)
870         .setSubchannelRef(subchannel)
871         .build();
872     Event event2 = new Event.Builder()
873         .setDescription("event2")
874         .setTimestampNanos(34)
875         .setSeverity(Severity.CT_INFO)
876         .setChannelRef(channel)
877         .build();
878 
879     ChannelStats stats =
880         toBuilder(channel.stats)
881             .setChannelTrace(
882                 new InternalChannelz.ChannelTrace.Builder()
883                     .setNumEventsLogged(1234)
884                     .setCreationTimeNanos(1000)
885                     .setEvents(Arrays.asList(event1, event2))
886                     .build())
887             .build();
888 
889     ChannelTraceEvent protoEvent1 = ChannelTraceEvent
890         .newBuilder()
891         .setDescription("event1")
892         .setTimestamp(Timestamps.fromNanos(12))
893         .setSeverity(ChannelTraceEvent.Severity.CT_ERROR)
894         .setSubchannelRef(subchannelRef)
895         .build();
896     ChannelTraceEvent protoEvent2 = ChannelTraceEvent
897         .newBuilder()
898         .setDescription("event2")
899         .setTimestamp(Timestamps.fromNanos(34))
900         .setSeverity(ChannelTraceEvent.Severity.CT_INFO)
901         .setChannelRef(channelRef)
902         .build();
903     ChannelData protoStats = channelData
904         .toBuilder()
905         .setTrace(channelTrace
906             .toBuilder()
907             .addAllEvents(Arrays.asList(protoEvent1, protoEvent2))
908             .build())
909         .build();
910     assertEquals(ChannelzProtoUtil.extractChannelData(stats), protoStats);
911   }
912 
toBuilder(ChannelStats stats)913   private static ChannelStats.Builder toBuilder(ChannelStats stats) {
914     ChannelStats.Builder builder = new ChannelStats.Builder()
915         .setTarget(stats.target)
916         .setState(stats.state)
917         .setCallsStarted(stats.callsStarted)
918         .setCallsSucceeded(stats.callsSucceeded)
919         .setCallsFailed(stats.callsFailed)
920         .setLastCallStartedNanos(stats.lastCallStartedNanos);
921     if (!stats.subchannels.isEmpty()) {
922       builder.setSubchannels(stats.subchannels);
923     }
924     if (!stats.sockets.isEmpty()) {
925       builder.setSockets(stats.sockets);
926     }
927     return builder;
928   }
929 
930 
toBuilder(SocketOptions options)931   private static SocketOptions.Builder toBuilder(SocketOptions options) {
932     SocketOptions.Builder builder = new SocketOptions.Builder()
933         .setSocketOptionTimeoutMillis(options.soTimeoutMillis)
934         .setSocketOptionLingerSeconds(options.lingerSeconds);
935     for (Entry<String, String> entry : options.others.entrySet()) {
936       builder.addOption(entry.getKey(), entry.getValue());
937     }
938     return builder;
939   }
940 
toBuilder(ServerStats stats)941   private static ServerStats.Builder toBuilder(ServerStats stats) {
942     return new ServerStats.Builder()
943         .setCallsStarted(stats.callsStarted)
944         .setCallsSucceeded(stats.callsSucceeded)
945         .setCallsFailed(stats.callsFailed)
946         .setLastCallStartedNanos(stats.lastCallStartedNanos)
947         .setListenSockets(stats.listenSockets);
948   }
949 }
950